} UNSAFE_END UNSAFE_ENTRY(void, Unsafe_PutLongVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong x)) { if (VM_Version::supports_cx8()) { MemoryAccess(thread, obj, offset).put_volatile<jlong>(x); } else { MemoryAccess(thread, obj, offset).put_jlong_locked(x); } } UNSAFE_END
} UNSAFE_END #ifndef SUPPORTS_NATIVE_CX8 // VM_Version::supports_cx8() is a surrogate for 'supports atomic long memory ops'. // // On platforms which do not support atomic compare-and-swap of jlong (8 byte) // values we have to use a lock-based scheme to enforce atomicity. This has to be // applied to all Unsafe operations that set the value of a jlong field. Even so // the compareAndSwapLong operation will not be atomic with respect to direct stores // to the field from Java code. It is important therefore that any Java code that // utilizes these Unsafe jlong operations does not perform direct stores. To permit // direct loads of the field from Java code we must also use Atomic::store within the // locked regions. And for good measure, in case there are direct stores, we also // employ Atomic::load within those regions. Note that the field in question must be // volatile and so must have atomic load/store accesses applied at the Java level. // // The locking scheme could utilize a range of strategies for controlling the locking // granularity: from a lock per-field through to a single global lock. The latter is // the simplest and is used for the current implementation. Note that the Java object // that contains the field, can not, in general, be used for locking. To do so can lead // to deadlocks as we may introduce locking into what appears to the Java code to be a // lock-free path. // // As all the locked-regions are very short and themselves non-blocking we can treat // them as leaf routines and elide safepoint checks (ie we don't perform any thread // state transitions even when blocking for the lock). Note that if we do choose to // add safepoint checks and thread state transitions, we must ensure that we calculate // the address of the field _after_ we have acquired the lock, else the object may have // been moved by the GC UNSAFE_ENTRY(jlong, Unsafe_GetLongVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { if (VM_Version::supports_cx8()) { return MemoryAccess(thread, obj, offset).get_volatile<jlong>(); } else { return MemoryAccess(thread, obj, offset).get_jlong_locked(); } } UNSAFE_END
int main(int argc, char ** argv) { char * binfilename = NULL; char * srcfilename = NULL; char * base = NULL; int i, cycle; bus32 tmp; bus8 inst_mem[4096]; /* instruction memory */ bus8 main_mem[4096]; /* main memory */ bus32 gnd; /* ground bus signal */ bus32 pc; /* program counter */ bus32 pc4; /* PC + 4 bus */ bus32 ir; /* instruction register */ bus32 jmp_addr; /* jump bus */ bus32 imm_sext; /* immediate sign extended bus */ bus32 imm_shext; /* immediate sign extended shifted bus */ bus32 branch_addr; /* branch bus */ bus32 mbranch_addr; /* mbranch bus */ /* control unit signals */ wire reg_write, reg_dest; wire mem_read, mem_write, mem_toreg; wire jump, branch; wire alu_src; bus3 alu_op; /* register memory signals & controls */ bus32 reg_in, reg_out1, reg_out2; bus32 reg_write_addr; /* main memory signal */ bus32 mem_out; /* alu signals */ wire zero; bus32 alu_src_val, alu_out; if (argc == 1) { fprintf(stderr, "usage: %s <filename>\n", argv[0]); return -1; } srcfilename = argv[1]; base = _parse_filename(srcfilename); if (!base) return -1; binfilename = malloc(sizeof(char) * (strlen(base) + 5)); sprintf(binfilename, "%s.bin", base); printf("assembling %s to %s...\n", srcfilename, binfilename); if (!Assemble(srcfilename, binfilename)) return -1; printf("loading %s into memory...\n", binfilename); LoadMemory(binfilename, inst_mem); /* load PC with initial VM address of 0x00000000 */ setbus32(gnd, "00000000000000000000000000000000"); setbus32(pc, gnd); /* initialize memory */ InitializeRegisterFileAccess(); for (i=0; i < 4096; i++) setbus8(main_mem[i], "00000000"); for(cycle=0; ; cycle++) { /* load IR with PC value */ MemoryAccess(ir, pc, gnd, '0', inst_mem); /* report fetched register values */ printf("cycle: %d, PC: %.32s (%d), IR: %.32s\n\t", cycle, pc, bus32toint(pc), ir); /* halt check */ if (bus32toint(ir) == 0x0000003F) { printf("\nmachine halted\n"); break; } /* PC + 4 data path */ RCAdder_32(pc4, gnd, pc, "00000000000000000000000000000100", '0'); /* jump data path */ shiftleft2x(jmp_addr, ir); jmp_addr[0] = pc4[0]; jmp_addr[1] = pc4[1]; jmp_addr[2] = pc4[2]; jmp_addr[3] = pc4[3]; /* sign extended / shifted immediate data path */ signextend(imm_sext, &ir[16]); shiftleft2x(imm_shext, imm_sext); /* control unit data path */ ControlUnit(ir, &ir[26], ®_write, ®_dest, &mem_read, &mem_write, &mem_toreg, &jump, &branch, &alu_src, alu_op); /* register memory data path - read */ Mux2_5(reg_write_addr, &ir[11], &ir[16], reg_dest); RegisterFileAccess(®_out1, ®_out2, &ir[6], &ir[11], reg_write_addr, reg_in, '0'); /* alu data path */ Mux2_32(alu_src_val, reg_out2, imm_sext, alu_src); zero = ALU(&alu_out, reg_out1, alu_src_val, alu_op); /* branch data path */ RCAdder_32(branch_addr, gnd, pc4, imm_shext, '0'); Mux2_32(mbranch_addr, pc4, branch_addr, AND2_1(zero, branch)); Mux2_32(pc, mbranch_addr, jmp_addr, jump); /* main memory data path */ MemoryAccess(mem_out, alu_out, reg_out2, mem_write, main_mem); Mux2_32(reg_in, alu_out, mem_out, mem_toreg); /* register memory data path - write */ RegisterFileAccess(®_out1, ®_out2, &ir[6], &ir[11], reg_write_addr, reg_in, reg_write); /* dump register memory and signal information */ for (i=0; i < 14; i++) { inttobusn(i, 5, tmp); RegisterFileAccess(®_out1, ®_out2, tmp, &ir[11], reg_write_addr, reg_in, '0'); printf("R%d: %d, ", i, bus32toint(reg_out1)); } printf("\b\b\n\tbranch_addr = %.32s (%d) jmp_addr = %.32s (%d)\n", branch_addr, bus32toint(branch_addr), jmp_addr, bus32toint(jmp_addr)); printf("\topcode = %.6s, imm_sext = %.32s (%d), imm_shext = %.32s (%d), PC+4 = %.32s (%d)\n", ir, imm_sext, bus32toint(imm_sext), imm_shext, bus32toint(imm_shext), pc4, bus32toint(pc4)); printf("\treg_write = %c, reg_dest = %c, mem_read = %c, mem_write = %c, mem_toreg = %c, jump = %c, branch = %c, alu_src = %c, alu_op = %.3s, zero = %c\n", reg_write, reg_dest, mem_read, mem_write, mem_toreg, jump, branch, alu_src, alu_op, zero); getchar(); } printf("\ntotal no. cycles: %d\n", cycle); // report end of program information free(binfilename); }