class Context(object): def __init__(self, instructions): self.registers = Registers() self.flags = Flags() self.instructions = instructions self.heap = Memory(size=40, mode=HEAP, start_address=0x0000) self.stack = Memory(size=40, mode=STACK, start_address=0xFFFF) self.registers.set(SP, 0xFFFF) def run(self): """ initialize the context and execute the first instruction """ self.registers.reset() def step(self): """ execute the next instruction whose address in the EIP value :return: """ self.registers.tick() self.flags.tick() self.heap.tick() self.stack.tick() next_address = self.registers.get(IP).value if next_address < len(self.instructions): next_instruction = self.instructions[next_address] next_instruction.execute(self) self.registers.set(IP, next_address + 1) return True else: return False
class RedPitayaControlService(BaseService): """Control server that runs on the RP that provides high-level methods.""" def __init__(self, **kwargs): self._cached_data = {} self.exposed_is_locked = None super().__init__() from registers import Registers self.registers = Registers(**kwargs) self.registers.connect(self, self.parameters) def run_acquiry_loop(self): """Starts a background process that keeps polling control and error signal. Every received value is pushed to `parameters.to_plot`.""" def data_received(is_raw, plot_data, data_uuid): # When a parameter is changed, `pause_acquisition` is set. # This means that the we should skip new data until we are sure that # it was recorded with the new settings. if not self.parameters.pause_acquisition.value: if data_uuid != self.data_uuid: return data_loaded = pickle.loads(plot_data) if not is_raw: is_locked = self.parameters.lock.value if not check_plot_data(is_locked, data_loaded): print( "warning: incorrect data received for lock state, ignoring!" ) return self.parameters.to_plot.value = plot_data self._generate_signal_stats(data_loaded) # update signal history (if in locked state) ( self.parameters.control_signal_history.value, self.parameters.monitor_signal_history.value, ) = update_signal_history( self.parameters.control_signal_history.value, self.parameters.monitor_signal_history.value, data_loaded, is_locked, self.parameters.control_signal_history_length.value, ) else: self.parameters.acquisition_raw_data.value = plot_data self.registers.run_data_acquisition(data_received) self.pause_acquisition() self.continue_acquisition() def _generate_signal_stats(self, to_plot): stats = {} for signal_name, signal in to_plot.items(): stats["%s_mean" % signal_name] = np.mean(signal) stats["%s_std" % signal_name] = np.std(signal) stats["%s_max" % signal_name] = np.max(signal) stats["%s_min" % signal_name] = np.min(signal) self.parameters.signal_stats.value = stats def exposed_write_data(self): """Syncs the parameters with the FPGA registers.""" self.registers.write_registers() def task_running(self): return (self.parameters.autolock_running.value or self.parameters.optimization_running.value or self.parameters.psd_acquisition_running.value or self.parameters.psd_optimization_running.value) def exposed_start_autolock(self, x0, x1, spectrum, additional_spectra=None): spectrum = pickle.loads(spectrum) # start_watching = self.parameters.watch_lock.value start_watching = False auto_offset = self.parameters.autolock_determine_offset.value if not self.task_running(): autolock = Autolock(self, self.parameters) self.parameters.task.value = autolock autolock.run( x0, x1, spectrum, should_watch_lock=start_watching, auto_offset=auto_offset, additional_spectra=pickle.loads(additional_spectra) if additional_spectra is not None else None, ) def exposed_start_optimization(self, x0, x1, spectrum): if not self.task_running(): optim = OptimizeSpectroscopy(self, self.parameters) self.parameters.task.value = optim optim.run(x0, x1, spectrum) def exposed_start_psd_acquisition(self): if not self.task_running(): self.parameters.task.value = PSDAcquisition(self, self.parameters) self.parameters.task.value.run() def exposed_start_pid_optimization(self): if not self.task_running(): self.parameters.task.value = PIDOptimization(self, self.parameters) self.parameters.task.value.run() def exposed_start_ramp(self): self.pause_acquisition() self.parameters.combined_offset.value = 0 self.parameters.lock.value = False self.exposed_write_data() self.continue_acquisition() def exposed_start_lock(self): self.pause_acquisition() self.parameters.lock.value = True self.exposed_write_data() self.continue_acquisition() def exposed_shutdown(self): """Kills the server.""" self.registers.acquisition.shutdown() _thread.interrupt_main() # we use SystemExit instead of os._exit because we want to call atexit # handlers raise SystemExit def exposed_get_server_version(self): import linien return linien.__version__ def exposed_get_restorable_parameters(self): return self.parameters._restorable_parameters def exposed_pause_acquisition(self): self.pause_acquisition() def exposed_continue_acquisition(self): self.continue_acquisition() def exposed_set_csr_direct(self, k, v): """Directly sets a CSR register. This method is intended for debugging. Normally, the FPGA should be controlled via manipulation of parameters.""" self.registers.set(k, v) def pause_acquisition(self): """Pause continuous acquisition. Call this before changing a parameter that alters the error / control signal. This way, no inconsistent signals reach the application. After setting the new parameter values, call `continue_acquisition`.""" self.parameters.pause_acquisition.value = True self.data_uuid = random() self.registers.acquisition.pause_acquisition() def continue_acquisition(self): """Continue acquisition after a short delay, when we are sure that the new parameters values have been written to the FPGA and that data that is now recorded is recorded with the correct parameters.""" self.parameters.pause_acquisition.value = False self.registers.acquisition.continue_acquisition(self.data_uuid)
class Interp: def __init__(self): self.cmds = { 'ADD': self.add, 'ADDU': self.add, 'SUB': self.add, 'SUBU': self.add, 'OR': self.add, 'AND': self.add, 'NOR': self.add, 'XOR': self.add, 'ADDI': self.addi, 'ADDIU': self.addi, 'SUBI': self.addi, 'SUBIU': self.addi, 'ANDI': self.addi, 'ORI': self.addi, 'XORI': self.addi, 'LI': self.li, 'MOVE': self.move, 'SLT': self.slt, 'SLTU': self.slt, 'SLTI': self.slti, 'SLTIU': self.slti, 'SLL': self.sll, 'SRL': self.sll, 'J': self.j, 'JAL': self.jal, 'JR': self.jr, 'BEQ': self.beq, 'BNE': self.beq, 'MULT': self.mult, 'MULTU': self.mult, 'DIV': self.div, 'DIVU': self.div, 'MFLO': self.mfhi, 'MFHI': self.mfhi, 'NOP': self.nop, 'PYEVAL': self.pyeval, 'PYJAL': self.pycall, 'SYSCALL': self.pysyscall, 'PYEXEC': self.pyexec, 'LW': self.lw, 'SW': self.lw, } self.regs = Registers() self.mem = Memory(32) def pcinc(self): pc = self.regs.get('pc') pc += 4 self.regs.set('pc', pc, special=True) def add(self, name, d, s, t): sval = self.regs.get(s) tval = self.regs.get(t) if name == 'SUB' or name == 'SUBU': sval -= tval elif name == 'OR': sval |= tval elif name == 'AND': sval &= tval elif name == 'XOR': sval ^= tval elif name == 'NOR': sval = ~(sval | tval) else: sval += tval if name == 'ADDU' or name == 'SUBU': sval = abs(sval) self.regs.set(d, sval) self.pcinc() def addi(self, name, d, s, i): val = self.regs.get(s) if name == 'SUBI' or name == 'SUBIU': val -= i elif name == 'ADDI' or name == 'ADDIU': val += i elif name == 'ANDI': val &= i elif name == 'ORI': val |= i elif name == 'XORI': val ^= i if name == 'ADDIU' or name == 'SUBIU': val = abs(val) self.regs.set(d, val) self.pcinc() def li(self, name, d, i): self.addi('ADDI', d, '$0', i) def move(self, name, d, s): self.add('ADD', d, s, '$0') def slt(self, name, d, a, b): aval = self.regs.get(a) bval = self.regs.get(b) if name == 'SLTU': aval = abs(aval) bval = abs(bval) if aval < bval: val = 1 else: val = 0 self.regs.set(d, val) self.pcinc() def slti(self, name, d, a, imm): aval = self.regs.get(a) self.regs.set(d, int(aval < imm)) self.pcinc() def sll(self, name, d, s, i): val = self.regs.get(s) if i > 5: i = 5 if name == 'SLL': val <<= i elif name == 'SRL': val >>= i self.regs.set(d, val) self.pcinc() def j(self, name, addr): self.regs.set('pc', addr, special=True) def jr(self, name, r): self.regs.set('pc', self.regs.get(r), special=True) def jal(self, name, addr): self.regs.set('$ra', self.regs.get('pc') + 4) self.j('J', addr) def beq(self, name, a, b, addr): aval = self.regs.get(a) bval = self.regs.get(b) if name == 'BEQ': truth = (aval == bval) elif name == 'BNE': truth = (bval != aval) if truth: self.j('J', addr) else: self.pcinc() def mult(self, name, a, b): aval = self.regs.get(a) bval = self.regs.get(b) if name == 'MULT' or name == 'MULTU': aval *= bval # We're going to store high and low just cause hi = (aval & 0xFFFFFFFF00000000) >> 0x20 lo = (aval & 0x00000000FFFFFFFF) self.regs.set('hi', int(hi), special=True) self.regs.set('lo', lo, special=True) self.pcinc() def div(self, name, a, b): aval = self.regs.get(a) bval = self.regs.get(b) if name == 'DIV' or name == 'DIVU': hi = aval / bval lo = aval % bval self.regs.set('hi', hi, special=True) self.regs.set('lo', lo, special=True) self.pcinc() def mfhi(self, name, to): if name == 'MFHI': val = self.regs.get('hi') elif name == 'MFLO': val = self.regs.get('lo') self.regs.set(to, val) self.pcinc() def nop(self, name): self.pcinc() def _ret_conv(self, val): if type(val) == int: return val try: res = int(val) except: res = 0xdeadbeef return res def pyeval(self, name, code): code = code[1:-1] res = eval(code) if type(res) in [list, tuple]: res0, res1 = res res0 = self._ret_conv(res0) res1 = self._ret_conv(res1) self.regs.set('$v0', res0) self.regs.set('$v1', res1) else: res = self._ret_conv(res) self.regs.set('$v0', res) self.pcinc() def pycall(self, name, func): args = [ self.regs.get('$a0'), self.regs.get('$a1'), self.regs.get('$a2'), self.regs.get('$a3') ] args = repr(tuple(filter(lambda x: x != 0, args))) code = '"' + func + args + '"' self.pyeval("PYEVAL", code) def pyexec(self, name, code): eval(code) self.pcinc() def pysyscall(self, name, func): args = (self.regs.get('$a0'), self.regs.get('$a1'), self.regs.get('$a2'), self.regs.get('$a3')) code = '"' + func + '(self,' + repr(args) + ')"' self.pyeval("PYEVAL", code) def _addr_decode(self, addr): import re match = re.match("((\d+)?\((.*?)\)|(.*))", addr) if match: g = match.groups() if g[1]: offset = int(g[1]) else: offset = 0 if g[2]: reg = g[2] elif g[3]: reg = g[3] else: offset = 0 reg = '$0' return offset, reg def lw(self, name, reg, addr): off, srcreg = self._addr_decode(addr) addr = self.regs.get(srcreg) + off if name == 'LW': self.regs.set(reg, self.mem.get(addr, 4)) elif name == 'SW': self.mem.set(addr, 4, self.regs.get(reg)) self.pcinc() def loader(self, code): self.mem.rom(0, code) def execute(self, args): inst = args[0] self.cmds[inst](*args) def run(self): while True: pc = self.regs.get('pc') inst = self.mem.rawget(pc) ij = [] for e in inst: ij.append(str(e)) ij[0] = "\033[1m" + ij[0] + "\033[0m" dbg = "\t\033[30m\033[1;34m*\033[0;37m%5d:\033[0m\t%s\033[0m\n" % ( pc, " ".join(ij)) sys.stderr.write(dbg) self.execute(inst)