pub fn tick(&mut self, trace_memory_access: bool, trace_path: &str) {
		let instruction_address = self.pc;

		if self.wfi {
			if (self.read_csr_raw(CSR_MIE_ADDRESS) & self.read_csr_raw(CSR_MIP_ADDRESS)) != 0 {
				self.wfi = false;
			}
			// @TODO: determine WFI latency
			return;
		}

		let word = match self.fetch_uncompress() {
			Ok(word) => word,
			Err(e) => {
				// Handle instruction page fault
				self.handle_exception(e, instruction_address);
				// @TODO: fix
				// e.g. add fetch latency
				return;
			}
		};

		let decode_result = self.decode(word, instruction_address);

		// Extra exit after decode stage, because we handle to/from host operation in decode stage.
		// Currently detect as exit when
		// * tohost address is set
		// * JAL to the identical address
		// * ECALL
		let pipeline_result = match decode_result {
			Ok(inst) => {
				// println!("inst={},pc={}", inst.get_name(), instruction_address);
				let cycles = inst.cycles;
				let result = (inst.operation)(self, word, instruction_address);
				self.x[0] = 0; // hardwired zero

				(result, cycles)
			}
			Err(()) => {
				// @TODO: illegal instructions
				//
				// Currently used for exitting.
				self.exit_signal = true;
				return;
			}
		};

		match pipeline_result.0 {
			Ok(()) => {
				self.mmu.clock = self.mmu.clock.wrapping_add(pipeline_result.1 as u64);
				self.clock = self.mmu.clock;
			}
			Err(e) => {
				// Handle pipeline traps
				self.clock = self.mmu.clock;
				self.handle_exception(e, instruction_address);
			}
		}

		if trace_memory_access == true {
			for i in 0..self.mmu.memory_access_trace.len() {
				let mut file = OpenOptions::new().append(true).open(trace_path).unwrap();

				file.write(
					format!(
						"0x{:016x} {} {}\n",
						self.mmu.memory_access_trace[i].address,
						match self.mmu.memory_access_trace[i].operation {
							MemoryAccessType::Read => "READ",
							MemoryAccessType::Write => "WRITE",
							_ => "",
						},
						self.mmu.memory_access_trace[i].cycle
					)
					.as_bytes(),
				)
				.unwrap();
			}
		}
		self.mmu.tick(&mut self.csr[CSR_MIP_ADDRESS as usize]);
		self.handle_interrupt(self.pc);
		// self.clock = self.clock.wrapping_add(1);

		// cpu core clock : mtime clock in clint = 8 : 1 is
		// just an arbiraty ratio.
		// @TODO: Implement more properly
		// self.write_csr_raw(CSR_CYCLE_ADDRESS, self.clock * 8);
		self.write_csr_raw(CSR_MCYCLE_ADDRESS, self.clock);
		self.write_csr_raw(CSR_HPMCOUNTER3_ADDRESS, self.mmu.l1_cache.hit_num);
		self.write_csr_raw(CSR_HPMCOUNTER4_ADDRESS, self.mmu.l1_cache.miss_num);
		self.write_csr_raw(CSR_HPMCOUNTER5_ADDRESS, self.mmu.l2_cache.hit_num);
		self.write_csr_raw(CSR_HPMCOUNTER6_ADDRESS, self.mmu.l2_cache.miss_num);
	}
/// Runs program one cycle. Fetch, decode, and execution are completed in a cycle so far.
Runs program one cycle. Fetch, decode, and execution are completed in a cycle so far.
Runs program one cycle . Fetch decode and execution are completed in a cycle so far .
pub fn tick(&mut self, trace_memory_access: bool, trace_path: &str) {
		let instruction_address = self.pc;
		if self.wfi {
			if (self.read_csr_raw(CSR_MIE_ADDRESS) & self.read_csr_raw(CSR_MIP_ADDRESS)) != 0 {
				self.wfi = false;
			}
			// @TODO: determine WFI latency
			return;
		}
		let word = match self.fetch_uncompress() {
			Ok(word) => word,
			Err(e) => {
				// Handle instruction page fault
				self.handle_exception(e, instruction_address);
				// @TODO: fix
				// e.g. add fetch latency
				return;
			}
		};
		let decode_result = self.decode(word, instruction_address);
		// Extra exit after decode stage, because we handle to/from host operation in decode stage.
		// Currently detect as exit when
		// * tohost address is set
		// * JAL to the identical address
		// * ECALL
		let pipeline_result = match decode_result {
			Ok(inst) => {
				// println!("inst={},pc={}", inst.get_name(), instruction_address);
				let cycles = inst.cycles;
				let result = (inst.operation)(self, word, instruction_address);
				self.x[0] = 0; // hardwired zero
				(result, cycles)
			}
			Err(()) => {
				// @TODO: illegal instructions
				//
				// Currently used for exitting.
				self.exit_signal = true;
				return;
			}
		};
		match pipeline_result.0 {
			Ok(()) => {
				self.mmu.clock = self.mmu.clock.wrapping_add(pipeline_result.1 as u64);
				self.clock = self.mmu.clock;
			}
			Err(e) => {
				// Handle pipeline traps
				self.clock = self.mmu.clock;
				self.handle_exception(e, instruction_address);
			}
		}
		if trace_memory_access == true {
			for i in 0..self.mmu.memory_access_trace.len() {
				let mut file = OpenOptions::new().append(true).open(trace_path).unwrap();
				file.write(
					format!(
						"0x{:016x} {} {}\n",
						self.mmu.memory_access_trace[i].address,
						match self.mmu.memory_access_trace[i].operation {
							MemoryAccessType::Read => "READ",
							MemoryAccessType::Write => "WRITE",
							_ => "",
						},
						self.mmu.memory_access_trace[i].cycle
					)
					.as_bytes(),
				)
				.unwrap();
			}
		}
		self.mmu.tick(&mut self.csr[CSR_MIP_ADDRESS as usize]);
		self.handle_interrupt(self.pc);
		// self.clock = self.clock.wrapping_add(1);
		// cpu core clock : mtime clock in clint = 8 : 1 is
		// just an arbiraty ratio.
		// @TODO: Implement more properly
		// self.write_csr_raw(CSR_CYCLE_ADDRESS, self.clock * 8);
		self.write_csr_raw(CSR_MCYCLE_ADDRESS, self.clock);
		self.write_csr_raw(CSR_HPMCOUNTER3_ADDRESS, self.mmu.l1_cache.hit_num);
		self.write_csr_raw(CSR_HPMCOUNTER4_ADDRESS, self.mmu.l1_cache.miss_num);
		self.write_csr_raw(CSR_HPMCOUNTER5_ADDRESS, self.mmu.l2_cache.hit_num);
		self.write_csr_raw(CSR_HPMCOUNTER6_ADDRESS, self.mmu.l2_cache.miss_num);
	}
pub fn tick ( & mut self , trace_memory_access : bool , trace_path : & str ) { let instruction_address = self . pc ; if self . wfi { if ( self . read_csr_raw ( CSR_MIE_ADDRESS ) & self . read_csr_raw ( CSR_MIP_ADDRESS ) ) != 0 { self . wfi = false ; } // @TODO: determine WFI latency return ; } let word = match self . fetch_uncompress ( ) { Ok ( word ) => word , Err ( e ) => { // Handle instruction page fault self . handle_exception ( e , instruction_address ) ; // @TODO: fix // e.g. add fetch latency return ; } } ; let decode_result = self . decode ( word , instruction_address ) ; // Extra exit after decode stage, because we handle to/from host operation in decode stage. // Currently detect as exit when // * tohost address is set // * JAL to the identical address // * ECALL let pipeline_result = match decode_result { Ok ( inst ) => { // println!("inst={},pc={}", inst.get_name(), instruction_address); let cycles = inst . cycles ; let result = ( inst . operation ) ( self , word , instruction_address ) ; self . x [ 0 ] = 0 ; // hardwired zero ( result , cycles ) } Err ( ( ) ) => { // @TODO: illegal instructions // // Currently used for exitting. self . exit_signal = true ; return ; } } ; match pipeline_result . 0 { Ok ( ( ) ) => { self . mmu . clock = self . mmu . clock . wrapping_add ( pipeline_result . 1 as u64 ) ; self . clock = self . mmu . clock ; } Err ( e ) => { // Handle pipeline traps self . clock = self . mmu . clock ; self . handle_exception ( e , instruction_address ) ; } } if trace_memory_access == true { for i in 0 .. self . mmu . memory_access_trace . len ( ) { let mut file = OpenOptions :: new ( ) . append ( true ) . open ( trace_path ) . unwrap ( ) ; file . write ( format ! ( " \n " self mmu memory_access_trace [ i ] address match self mmu memory_access_trace [ i ] operation { MemoryAccessType Read " " MemoryAccessType Write " " " " } self mmu memory_access_trace [ i ] cycle ) . as_bytes ( ) , ) . unwrap ( ) ; } } self . mmu . tick ( & mut self . csr [ CSR_MIP_ADDRESS as usize ] ) ; self . handle_interrupt ( self . pc ) ; // self.clock = self.clock.wrapping_add(1); // cpu core clock : mtime clock in clint = 8 : 1 is // just an arbiraty ratio. // @TODO: Implement more properly // self.write_csr_raw(CSR_CYCLE_ADDRESS, self.clock * 8); self . write_csr_raw ( CSR_MCYCLE_ADDRESS , self . clock ) ; self . write_csr_raw ( CSR_HPMCOUNTER3_ADDRESS , self . mmu . l1_cache . hit_num ) ; self . write_csr_raw ( CSR_HPMCOUNTER4_ADDRESS , self . mmu . l1_cache . miss_num ) ; self . write_csr_raw ( CSR_HPMCOUNTER5_ADDRESS , self . mmu . l2_cache . hit_num ) ; self . write_csr_raw ( CSR_HPMCOUNTER6_ADDRESS , self . mmu . l2_cache . miss_num ) ; }
Runs program one cycle.
Runs program one cycle .
&mut self
trace_memory_access
bool
trace_path
&str