Franck Pommereau

imported existing project

syntax: glob
*.pyc
*~
,*
# Exo: mettre en place un traitant pour
# l'interruption d'horloge qui incrémente
# le compteur en RAM
IRQ0: # programme principal
dec IP # reste sur place en attendant IRQ2
IRQ2: # interruption d'horloge
set R0 0xE2 # adresse du compteur
load R0 R1
inc R1
save R1 R0
iret
# Exo: copie d'un tableau
tab1:
=5 # longueur
=0x1111 # données reconnaissables
=0x2222
=0x3333
=0x4444
=0x5555
tab2: # idem avec d'autres données
=5
=0xAAAA
=0xBBBB
=0xCCCC
=0xDDDD
=0xEEEE
IRQ0:
set R4 @loop
set R5 @end
set R6 @error
# on charge les infos des tableaux
# tab1 => R0 et R1
set R0 @tab1
load R0 R1
inc R0
# tab2 => R2 et R3
set R2 @tab2
load R2 R3
inc R2
# on compare R1 et R3 (longueurs)
eq R1 R3
jz RF R6 # si R1/=R2, on a une erreur
loop:
jz R1 R5 # si R1=0 => fini
load R0 R7 # on charge un mot de tab1
save R7 R2 # on le copie dans tab2
inc R0
inc R2
dec R1
jmp R4 # on boucle
end:
dec ip # boucle infinie
# on peut regarder la RAM
error:
halt # erreur, on éteind la machine
# Exo: mettre en place un traitant pour une
# erreur de périphérique qui éteind la
# machine
IRQ0:
set R0 0x0111 # RAM => commande inconnue
bus0 R1 R2
dec IP # on n'arrivera pas là
IRQ1:
halt
# structure générale de type if/then/else
# ce n'est pas un exemple à exécuter, il
# manque un contexte
# ici : instructions avant le if
# début du if
set R0 @then
set R1 @else
set R2 @end_if
# ici : on réalise le test, de façon à se
# ramener à tester si un registre est à
# zéro, par exemple R9
jz R9 R0 # si R0=0 => then
jmp R1 # sinon => else
then:
# ici : instructions du then
jmp R2 # ensuite on continue au end if
else:
# ici : instructions du else
# ensuite on contine directement au end if
end_if:
# ici : instructions après le end if
# structure générale de type loop/end loop
# ce n'est pas un exemple à exécuter, il
# manque un contexte
# ici : instructions avant le loop
# début du loop
set R0 @loop
set R1 @end_loop
loop:
# ici : instructions avant exit when
# exemple : exit when R5=0
jz R5 R1 # so R5=0 => fini
# ici : instructions après exit when
# on reboucle avant le end loop
jmp R0
end_loop:
# ici : instructions après le end loop
# Exo: faire un traitant pour l'IRQ3 qui
# affiche à lcran le registre R0
IRQ0:
set R0 'H'
intr 3
set R0 'e'
intr 3
set R0 'l'
intr 3
set R0 'l'
intr 3
set R0 'o'
intr 3
halt
IRQ3:
set R1 0x1011
bus1 R0 R2
iret
# Exo: faire un programme qui affiche une
# chaîne à lcran
str: # les données de la chaîne
='H'
='e'
='l'
='l'
='o'
=' '
='w'
='o'
='r'
='l'
='d'
='!'
=0 # on utilise 0 comme marqueur de fin de
# chaîne (comme en C, C++, Python, etc.)
IRQ0: # début
set R0 @str
set R2 @loop
set R3 @end
loop: # boucle pour afficher chaque caractère
load R0 R1 # on lit le caractère
jz R1 R3 # si c'est le marqueur 0 => fini
set R3 0x1011 # sinon, on l'affiche
bus3 R1 R4
inc R0 # on avance le pointeur sur le
# caractère suivant
jmp R2 # on boucle
end:
halt
# Exo: faire un programme qui somme les
# entiers d'un tableau
tab: # le tableau
=5 # premier mot = longueur
=1 # suite = données
=2
=3
=4
=5
IRQ0: # début
set R0 @tab # R0 = pointeur sur le tableau
load R0 R1 # R1 = longueur du tableau
inc R0 # R0 = pointeur sur la première case
set R2 @loop
set R3 @end
rst R4 # on calculera la somme dans R4
loop:
jz R1 R3 # si longueur = 0 => fin
load R0 R5 # sinon, on lit un mot du tableau
add R4 R5
dec R1 # on a traité un mot, il en reste
# donc un de moins
inc R0 # on pointe sur le suivant
jmp R2 # on boucle
end:
halt # ici, R4 vaut 0x000F = 15 = 1+2+3+4+5
#!/usr/bin/env python
import pygtk
pygtk.require("2.0")
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
warnings.filterwarnings("ignore", category=RuntimeWarning,
message="tmpnam is a potential security risk to your program")
from bones.gui import editor
editor.MainWindow()
File mode changed
This diff is collapsed. Click to expand it.
from bones.words import hexa_to_int
commands = { "000" : "start",
"001" : "stop",
"002" : "reset",
"010" : "read",
"011" : "write",
"012" : "interrupt" }
codes = {}
for num, com in commands.items() :
codes[com] = num
class Bus :
def __init__ (self, view, rom, *devices) :
self.view = view
self._dev = devices
self._rom = rom
def reset (self) :
self.view.reset()
for dev in range(len(self._dev)) :
self.view.select(dev, "reset")
command = "%01x%s" % (dev, codes["reset"])
self.view.transmit("0000", "0000", command)
self._dev[dev].call("0000", "0000", command)
def copy_rom (self) :
self._dev[0].rom(self._rom)
def call (self, data, address, command) :
self.view.update(data, address, command)
dev, com = hexa_to_int(command[0]), command[1:]
try :
self.view.select(dev, commands[com])
except KeyError :
self.view.select(dev, com)
self.view.transmit(data, address, "0" + com)
d, a, c = self._dev[dev].call(data, address, "0" + com)
self.view.finish(d, a, c)
return d, a, c
This diff is collapsed. Click to expand it.
import bones.cpu
opname = {}
opargs = {}
opdoc = {}
for attr in dir(bones.cpu.Cpu) :
if not attr.startswith("_op_") :
continue
spec, doc = getattr(bones.cpu.Cpu, attr).__doc__.split("\n", 1)
parts = spec.strip().split(" ")
codeop = parts.pop(0)
name = attr[4:]
args = [p.split(":") for p in parts]
opname[codeop] = name
opargs[codeop] = args
opdoc[codeop] = doc.strip()
codeops = opname.keys()
codeops.sort()
html = open(",cpudoc.html", "w")
test = open(",cputest.asm", "w")
tex = open(",cpudoc.tex", "w")
html.write("<html><head><title>Assembler syntax</title></head>\n")
html.write("<body>\n")
tex.write("\\documentclass{article}\n"
"\\parindent=-1em \\leftskip=1em\n \\parskip=0pt plus 5pt"
"\\usepackage[T1]{fontenc}\n"
"\\usepackage{multicol}\n"
"\\usepackage[dvips,margin=1cm,landscape,a4paper,ignoreall,noheadfoot]{geometry}\n"
"\\pagestyle{empty}\n"
"\\begin{document}\n"
"\\begin{center}\\bf Bones: CPU instructions\\end{center}"
"\\begin{multicols}{3}\n")
style = { 0 : "darkgreen",
1 : "darkblue" }
for op in codeops :
html.write('<p><code><b style="color:darkred">%s</b>' % opname[op])
tex.write("\\textsf{\\textbf{%s}" % opname[op])
test.write(opname[op])
num = {}
for i in range(len(opargs[op])) :
html.write("&nbsp;" * 2)
html.write('<i style="color:%s">%s</i>' % (style[i],
opargs[op][i][0]))
num[opargs[op][i][0]] = i
tex.write("~\\textit{%s}" % opargs[op][i][0])
test.write(" " + opargs[op][i][1])
html.write('</code><br>\n<code style="color:gray">(codeop=%s' % op)
tex.write("}\\\\\n$\\triangleright$ codeop=\\texttt{%s}" % op)
for i in range(len(opargs[op])) :
html.write(", <i>%s</i>:%s" % tuple(opargs[op][i]))
tex.write(", \\textit{%s}$\,:\,$%s" % tuple(opargs[op][i]))
html.write(")</code><br>\n")
tex.write("\\\\\n")
doc = opdoc[op].split("'")
while len(doc) > 0 :
part = doc.pop(0)
html.write(part)
tex.write(part)
if len(doc) > 0 :
arg = doc.pop(0)
html.write('<code><i style="color:%s">%s</i></code>'
% (style[num[arg]], arg))
tex.write("\\textit{%s}" % arg)
html.write("\n")
tex.write("\n\n")
test.write("\n")
html.write("</body></html>")
html.close()
tex.write("\\end{multicols}\n"
"\\end{document}\n")
tex.close()
test.close()
from bones.bus import commands
class DeviceError (Exception) :
pass
class Device :
"dummy device"
def __init__ (self, view) :
self.view = view
def call (self, data, address, command) :
try :
handler = getattr(self, "_call_" + commands[command[1:]])
except KeyError :
raise DeviceError, "unknown command"
except AttributeError :
raise DeviceError, "unsupported command"
return handler(data, address, command)
def _call_start (self, data, address, command) :
return data, address, command
def _call_stop (self, data, address, command) :
return data, address, command
def _call_reset (self, data, address, command) :
self._call_stop(data, address, command)
return self._call_start(data, address, command)
from bones.words import hexa_to_int
from bones.dev import Device
class RAM (Device) :
"random access memory"
def __init__ (self, view, size=0x10000) :
Device.__init__(self, view)
self._data = ["0000"] * size
def _call_write (self, data, address, command) :
index = hexa_to_int(address)
self.view.update(address, data)
self._data[index] = data
return data, address, command
def _call_read (self, data, address, command) :
index = hexa_to_int(address)
self.view.update(address, self._data[index])
return self._data[index], address, command
def rom (self, rom) :
data = rom.data()
self._data = data + ["0000"] * (len(self._data) - len(data))
self.view.reset(self._data, len(data))
class ROM (Device) :
"read-only memory"
def __init__ (self, view, bios) :
Device.__init__(self, view)
if isinstance(bios, file) :
self._data = [w.strip() for w in bios]
elif isinstance(bios, str) :
self._data = [w.strip() for w in open(bios)]
elif isinstance(bios, list) :
self._data = bios[:]
else :
raise TypeError, "invalid bios"
def _call_start (self, data, address, command) :
return data, address, command
def data (self) :
return self._data[:]
from bones.dev import Device
from bones.words import hexa_to_int
class TextScreen (Device) :
"text screen"
def _call_start (self, data, address, command) :
self.view.clear()
return data, address, command
def _call_write (self, data, address, command) :
fg, bg, char = data[0], data[1], data[2:]
self.view.put(chr(hexa_to_int(char)), fg, bg)
return data, address, command
File mode changed
import gtk
from bones.gui.cpu import CycleGui
import bones.words
class BusGui (gtk.HBox) :
def __init__ (self, size=16) :
gtk.HBox.__init__(self, spacing=2)
self.set_border_width(2)
self._box = gtk.VBox()
self.add(self._box)
frame = gtk.Frame(" Bus ")
self._box.pack_end(frame, gtk.FALSE, gtk.TRUE)
sizer = gtk.SizeGroup(gtk.SIZE_GROUP_VERTICAL)
left = gtk.VBox(spacing=2)
frame.add(left)
right = gtk.VBox(spacing=2)
self.add(right)
self.dbox = gtk.HBox(spacing=2)
right.add(self.dbox)
self.cycle = CycleGui(("idle", "Idle"),
("select", (gtk.Entry(), 0.5)),
("transmit", "Transmitting"))
left.pack_start(self.cycle, gtk.FALSE, gtk.TRUE)
left.add(gtk.HSeparator())
self._dev = {}
self._frame = {}
for dev in bones.words.hexa_words(size) :
handle = gtk.HandleBox()
handle.set_shadow_type(gtk.SHADOW_NONE)
handle.set_handle_position(gtk.POS_TOP)
frame = gtk.Frame(" [dev %s] " % dev)
self.dbox.add(frame)
frame.add(handle)
self._dev[dev] = handle
self._frame[dev] = frame
handle.connect("child-detached", self._detach)
for name in ["Command", "Data", "Address"] :
label = gtk.Label(" %s " % name)
left.pack_start(label, gtk.FALSE, gtk.TRUE)
sizer.add_widget(label)
entry = gtk.Entry()
right.pack_start(entry, gtk.FALSE, gtk.TRUE)
sizer.add_widget(entry)
entry.set_editable(gtk.FALSE)
entry.set_property("can-focus", gtk.FALSE)
entry.set_text("0000")
setattr(self, name.lower(), entry)
def _detach (self, handle, *args) :
self.get_toplevel().resize(1, 1)
def reset (self) :
self.update("0000", "0000", "0000")
self.cycle.set_state("idle")
def update (self, data, address, command) :
self.data.set_text(data)
self.address.set_text(address)
self.command.set_text(command)
def plug (self, device, slot) :
device.set_border_width(1)
if slot in self._dev :
self._dev[slot].add(device)
try :
self._frame[slot].set_label(" [dev %s] %s "
% (slot, device.name))
except :
pass
else :
frame = gtk.Frame(" %s " % slot)
self._box.add(frame)
frame.add(device)
if __name__ == "__main__" :
win = gtk.Window()
def quit (*args) :
gtk.main_quit()
win.connect("delete-event", quit)
bus = BusGui(4)
win.add(bus)
win.show_all()
gtk.mainloop()
import gtk
from bones.gui.editor import _img
import bones.gui.mainboard, bones.gui.memory, bones.gui.screen, bones.gui.cpu
class ControlPanel (gtk.HandleBox) :
def __init__ (self) :
gtk.HandleBox.__init__(self)
self.connect("child-attached", self._attach)
self.connect("child-detached", self._detach)
self._bar = gtk.Toolbar()
self.add(self._bar)
self._bar.set_style(gtk.TOOLBAR_ICONS)
self.next = self._bar.append_item("Next event", "Next event", None,
_img(gtk.STOCK_GO_FORWARD), None)
self.cycle = self._bar.append_item("Next cycle", "Next cycle", None,
_img(gtk.STOCK_GOTO_LAST), None)
self._bar.append_space()
self.run = self._bar.append_item("Execute", "Execute automatically",
None, _img(gtk.STOCK_EXECUTE), None)
self.speed = gtk.HScale()
self.speed.set_digits(0)
self.speed.set_value_pos(gtk.POS_RIGHT)
self.speed.set_range(1, 100)
self.speed.set_value(10)
self.speed.set_property("can-focus", gtk.FALSE)
x, y = self.speed.size_request()
self.speed.set_size_request(x*4, y)
self._bar.append_widget(self.speed, "Execution speed", None)
self.stop = self._bar.append_item("Stop", "Stop execution",
None, _img(gtk.STOCK_CANCEL), None)
self.stop.set_sensitive(gtk.FALSE)
self._bar.append_space()
self.quit = self._bar.append_item("Quit", "Quit Bones", None,
_img(gtk.STOCK_QUIT), None)
def _detach (self, *args) :
self._bar.set_style(gtk.TOOLBAR_BOTH)
def _attach (self, *args) :
self._bar.set_style(gtk.TOOLBAR_ICONS)
def disable (self) :
for widget in [self.next, self.cycle, self.run, self.speed, self.stop] :
widget.set_sensitive(gtk.FALSE)
class CursorChanger :
def __init__ (self, win) :
self._win = win
self._gdk_win = win.window
self._wait = gtk.gdk.Cursor(gtk.gdk.WATCH)
self._normal = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
self._count = 0
def _flush (self) :
while gtk.events_pending() :
gtk.main_iteration(gtk.FALSE)
def wait (self) :
if self._count == 0 :
self._win.set_sensitive(gtk.FALSE)
self._gdk_win.set_cursor(self._wait)
self._flush()
self._count += 1
def normal (self) :
self._count -= 1
if self._count == 0 :
self._gdk_win.set_cursor(self._normal)
self._win.set_sensitive(gtk.TRUE)
class BonesWindow (gtk.Window) :
def __init__ (self, rom, *devices) :
gtk.Window.__init__(self)
self.set_title("Bones")
self.connect("destroy", self._quit)
self.connect("delete_event", self._quit)
box = gtk.VBox()
self.add(box)
self.control = ControlPanel()
box.add(self.control)
self.rom = bones.gui.memory.ROMGui(rom)
self.cpu = bones.gui.cpu.CPUGui()
if len(devices) > 0 :
self.ram = devices[0]
self.dev = devices
else :
self.ram = bones.gui.memory.MemoryGui()
self.dev = [self.ram, bones.gui.screen.TextScreenGui()]
self.bus = bones.gui.bus.BusGui(len(self.dev))
self.main = bones.gui.mainboard.MainBoardGui(self.rom, self.cpu,
self.bus, *self.dev)
box.add(self.main)
self.control.quit.connect("clicked", self._quit)
def show_all (self) :
gtk.Window.show_all(self)
self.cpu.control.clock.hide()
def run (self) :
self.show_all()
self.cursor = CursorChanger(self)
gtk.mainloop()
def _quit (self, *args) :
gtk.main_quit()
if __name__ == "__main__" :
win = BonesWindow([])
win.main.irq.assign("0", "boot")
win.main.irq.assign("1", "hardware error")
win.main.irq.assign("2", "clock")
win.run()
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
import gtk
class LogView (gtk.ScrolledWindow) :
def __init__ (self, max=100) :
self._len = 0
self._max = max
gtk.ScrolledWindow.__init__(self)
self.set_size_request(-1, 60)
self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
self._view = gtk.TextView()
self.add(self._view)
self._view.set_editable(gtk.FALSE)
self._view.set_cursor_visible(gtk.FALSE)
self._view.set_wrap_mode(gtk.WRAP_NONE)
self._view.set_justification(gtk.JUSTIFY_LEFT)
self._buff = self._view.get_buffer()
self._tag = {}
for name, color in [("info", "black"), ("error", "darkred"),
("warn", "darkblue"), ("debug", "darkgray")] :
self._tag[name] = self._buff.create_tag(None, foreground=color)
def __len__ (self) :
return self._len
def clear (self) :
self._buff.set_text("")
self._len = 0
def log (self, line, tag=None) :
buff = self._buff
if self._len == self._max :
start = buff.get_start_iter()
end = start.copy()
end.forward_line()
buff.delete(start, end)
else :
self._len += 1
if self._len > 1 :
buff.insert(buff.get_end_iter(), "\n")
pos = buff.create_mark(None, buff.get_end_iter(), gtk.TRUE)
if tag is None :
tag = self._tag["info"]
buff.insert_with_tags(buff.get_end_iter(), line.strip(), tag)
self._view.scroll_to_mark(pos, 0.0, gtk.TRUE, 0.0, 1.0)
def info (self, text) :
for line in text.split("\n") :
self.log(line, self._tag["info"])
def error (self, text) :
for line in text.split("\n") :
self.log(line, self._tag["error"])
def warn (self, text) :
for line in text.split("\n") :
self.log(line, self._tag["warn"])
def debug (self, text) :
for line in text.split("\n") :
self.log(line, self._tag["debug"])
if __name__ == "__main__" :
win = gtk.Window()
def quit (*args) :
gtk.main_quit()
win.connect("delete-event", quit)
box = gtk.VBox()
win.add(box)
log = LogView(5)
box.add(log)
def click (*args) :
log.log(args[-1], log._tag[args[-1]])
for name in ["info", "error", "warn", "debug"] :
but = gtk.Button(name)
box.add(but)
but.connect("clicked", click, name)
win.show_all()
gtk.mainloop()
import gtk
import bones.words, bones.cpu
import bones.gui.cpu, bones.gui.bus, bones.gui.memory
class IRQGui (gtk.Table) :
def __init__ (self) :
gtk.Table.__init__(self, len(bones.cpu.InterruptVector.names), 2)
self._irq = {}
row = 0
for name in bones.cpu.InterruptVector.names :
label = gtk.Label(name + ": ")
self.attach(label, 0, 1, row, row+1)
self._irq[name] = gtk.Label("free")
self._irq[name].set_alignment(0.0, 0.5)
self._irq[name].set_sensitive(gtk.FALSE)
self.attach(self._irq[name], 1, 2, row, row+1)
row += 1
def assign (self, name, device) :
self._irq[name].set_text(device.strip())
self._irq[name].set_sensitive(gtk.TRUE)
class MainBoardGui (gtk.HBox) :
def __init__ (self, rom, cpu=None, bus=None, *devices) :
gtk.HBox.__init__(self, spacing=2)
if cpu is None :
self.cpu = bones.gui.cpu.CPUGui()
else :
self.cpu = cpu
self.add(self.cpu)
if bus is None :
self.bus = bones.gui.bus.BusGui(len(devices))
else :
self.bus = bus
self.add(self.bus)
for dev, num in zip(devices, bones.words.hexa_words(len(devices))) :
self.bus.plug(dev, num)
self.irq = IRQGui()
self.bus.plug(self.irq, "IRQ")
self.rom = rom
self.bus.plug(self.rom, "ROM")
if __name__ == "__main__" :
import bones.gui.screen
win = gtk.Window()
def quit (*args) :
gtk.main_quit()
win.connect("delete-event", quit)
m = MainBoardGui(bones.gui.memory.ROMGui([]),
None, None,
bones.gui.memory.MemoryGui(),
bones.gui.screen.TextScreenGui())
m.irq.assign("0", "boot")
m.irq.assign("1", "hardware error")
m.irq.assign("2", "clock")
win.add(m)
win.show_all()
gtk.mainloop()
import gtk, gobject
import bones.words as words
from bones.asm import Word, BiosAssembler
class MemoryGui (gtk.HBox) :
name = "RAM"
columns=["Address", "Value"]
def __init__ (self, clickable=True) :
gtk.HBox.__init__(self)
self.set_size_request(160, 100)
self._store = gtk.ListStore(*([gobject.TYPE_STRING]
* len(self.columns)))
self._view = gtk.TreeView(self._store)
self.add(self._view)
self._scroll = gtk.VScrollbar(self._view.get_vadjustment())
self.pack_start(self._scroll, gtk.FALSE, gtk.TRUE, 0)
self._focus = gtk.EventBox()
self.pack_start(self._focus, gtk.FALSE, gtk.FALSE, 0)
self._focus.set_property("can-focus", gtk.TRUE)
self._focus.grab_focus()
self.set_focus_child(self._focus)
self._select = self._view.get_selection()
self._select.set_mode(gtk.SELECTION_MULTIPLE)
for col in range(len(self.columns)) :
cell = gtk.CellRendererText()
tvcol = gtk.TreeViewColumn(self.columns[col], cell)
self._view.append_column(tvcol)
tvcol.add_attribute(cell, 'text', col)
if clickable and (col == 0) :
tvcol.set_clickable(gtk.TRUE)
tvcol.connect("clicked", self.show_current)
self._last = -1
self._to_add = []
self._view.connect("scroll-event", self._scroll_event)
def _scroll_event (self, widget, event, *args) :
self._scroll.event(event)
def _append (self, value) :
self._last += 1
self._store.append([("%04x" % self._last).upper(), value.upper()])
def reset (self, data, used) :
self._view.freeze_child_notify()
self._store.clear()
for value in data[:used] :
self._append(value)
self._select.unselect_all()
self._view.thaw_child_notify()
self._last = used - 1
self._to_add = data[used:]
#gobject.idle_add(self._add)
def _add (self, *args) :
if len(self._to_add) == 0 :
return gtk.FALSE
else :
self._append(self._to_add.pop(0))
return gtk.TRUE
def update (self, addr, value) :
index = words.hexa_to_int(addr)
while self._last < index :
self._append(self._to_add.pop(0))
self._store.set_value(self._store.get_iter(index), 1, value)
self.select(addr)
def select (self, addr) :
index = words.hexa_to_int(addr)
self._select.unselect_all()
self._select.select_path(index)
self.show_current()
def show_current (self, *args) :
def scroll (treemodel, path, iter) :
self._view.scroll_to_cell(path, None, gtk.TRUE, 0.5, 0.0)
self._select.selected_foreach(scroll)
self._focus.grab_focus()
def current (self) :
self._current = None
def find (treemodel, path, iter) :
self._current = path[0]
self._select.selected_foreach(find)
return self._current
if True and (__name__ == "__main__") :
from bones.dev.memory import RAM
win = gtk.Window()
def quit (*args) :
gtk.main_quit()
win.connect("delete-event", quit)
mem = MemoryGui()
win.add(mem)
words = ["1012", "3011", "6010"]
addr = 0
def update (*args) :
global addr
if len(words) > 0 :
mem._append(addr, words.pop(0))
addr += 1
return True
else :
mem.select(1)
return False
gobject.timeout_add(500, update)
win.show_all()
gtk.mainloop()
class DisassemblyMemoryGui (MemoryGui) :
columns = ["Address", "Value", "Disassembly"]
def __init__ (self) :
MemoryGui.__init__(self, False)
self.set_size_request(280, 100)
self._bios = BiosAssembler().bios
def _append (self, value) :
self._last += 1
try :
if self._last < len(self._bios) :
asm = self._bios[self._last]
else :
asm = Word(value).asm()
except :
asm = "invalid instruction"
self._store.append([("%04x" % self._last).upper(), value, asm])
class ROMWindow (gtk.Window) :
def __init__ (self, data) :
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
self.set_title("ROM content")
vbox = gtk.VBox()
self.add(vbox)
rom = DisassemblyMemoryGui()
rom.reset(data, len(data))
rom.set_border_width(1)
vbox.add(rom)
vbox.pack_start(gtk.HSeparator(), gtk.FALSE, gtk.FALSE, 0)
bbox = gtk.HButtonBox()
vbox.pack_end(bbox, gtk.FALSE, gtk.FALSE, 0)
bbox.set_layout(gtk.BUTTONBOX_END)
bbox.set_border_width(2)
button = gtk.Button(stock=gtk.STOCK_CLOSE)
accel = gtk.AccelGroup()
self.add_accel_group(accel)
button.add_accelerator("clicked", accel,
gtk.gdk.keyval_from_name("Escape"),
(), gtk.ACCEL_LOCKED)
bbox.add(button)
button.connect("clicked", self._close)
self.set_size_request(300, 400)
def _close (self, *args) :
self.destroy()
class ROMGui (gtk.VBox) :
def __init__ (self, data) :
gtk.VBox.__init__(self, spacing=2)
self.set_border_width(2)
self._data = data
self._length = gtk.Label("length: %d words" % len(data))
self.add(self._length)
self._button = gtk.Button("Show content")
self._button.set_property("can-focus", gtk.FALSE)
self._button.set_border_width(2)
self.pack_start(self._button, gtk.FALSE, gtk.TRUE)
self._button.connect("clicked", self._show)
def _show (self, *args) :
self._button.set_sensitive(gtk.FALSE)
win = ROMWindow(self._data)
win.connect("destroy", self._hide)
win.show_all()
def _hide (self, *args) :
self._button.set_sensitive(gtk.TRUE)
self._button.queue_draw()
if False and (__name__ == "__main__") :
from bones.dev.memory import ROM
from bones.bus import BusContent
win = gtk.Window()
def quit (*args) :
gtk.main_quit()
win.connect("delete-event", quit)
mem = ROMGui()
win.add(mem)
rom = ROM(mem, "/home/franck/work/tools/bones/,test.bios")
bus = BusContent()
com = [0x0012, 0x0011, 0x0010]
def update (*args) :
try :
bus.data, bus.address, bus.command = 0x1234, 0x0001, com.pop()
rom.call(bus)
print bus
except Exception, e:
print "device error:", e
return len(com) > 0
gobject.timeout_add(500, update)
win.show_all()
gtk.mainloop()
import gtk, pango, gobject
class TextScreenGui (gtk.VBox) :
name = "Text screen"
def __init__ (self, width=40, height=12, tab_size=4) :
gtk.VBox.__init__(self)
self._view = gtk.TextView()
hbox = gtk.HBox()
self.add(gtk.VBox())
self.pack_start(hbox, gtk.FALSE, gtk.FALSE, 0)
self.add(gtk.VBox())
hbox.add(gtk.HBox())
frame = gtk.Frame()
hbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
hbox.add(gtk.HBox())
frame.add(self._view)
frame.set_shadow_type(gtk.SHADOW_OUT)
self._buff = self._view.get_buffer()
self._view.set_editable(gtk.FALSE)
self._view.set_cursor_visible(gtk.FALSE)
self._view.set_wrap_mode(gtk.WRAP_NONE)
self._view.set_justification(gtk.JUSTIFY_LEFT)
self._view.set_border_width(4)
black = gtk.gdk.color_parse("black")
white = gtk.gdk.color_parse("white")
self._view.modify_bg(gtk.STATE_NORMAL, black)
self._view.modify_fg(gtk.STATE_NORMAL, white)
self._view.modify_base(gtk.STATE_NORMAL, black)
self._view.modify_text(gtk.STATE_NORMAL, white)
fgcol = { "0" : "#FFFFFF",
"1" : "#000000",
"2" : "#FF0000",
"3" : "#00FF00",
"4" : "#0000FF",
"5" : "#00FFFF",
"6" : "#FF00FF",
"7" : "#FFFF00",
"8" : "#800000",
"9" : "#008000",
"A" : "#000080",
"B" : "#008080",
"C" : "#800080",
"D" : "#808000",
"E" : "#808080",
"F" : "#C0C0C0" }
bgcol = fgcol.copy()
bgcol.update({"0" : "#000000", "1" : "#FFFFFF"})
self._font = {}
for fg in fgcol :
for bg in bgcol :
self._font[fg+bg] = self._buff.create_tag(family="Monospace",
foreground=fgcol[fg],
background=bgcol[bg])
self._set_size = True
self._height = height
self._width = width
self._tab_size = tab_size
self._do_blink = True
self._blank()
def _blank (self) :
self._buff.set_text("")
self._buff.insert_with_tags(self._buff.get_end_iter(),
"\n".join([" " * self._width]
* self._height),
self._font["10"])
def _size (self, *args) :
if self._set_size :
self._view.set_size_request(*self.size_request())
self._buff.set_text("")
self._set_size = False
gobject.timeout_add(500, self._blink)
def _end (self) :
result = self._buff.get_end_iter()
if not self._do_blink :
result.backward_char()
return result
def _blink (self, *args) :
if self._do_blink :
self._buff.insert_with_tags(self._buff.get_end_iter(), "_",
self._font["00"])
else :
self._buff.delete(self._end(), self._buff.get_end_iter())
self._do_blink = not self._do_blink
return gtk.TRUE
def _put (self, char, fg, bg) :
self._size()
self._buff.insert_with_tags(self._end(), char, self._font[fg+bg])
height = self._buff.get_line_count()
line = self._buff.get_text(self._buff.get_iter_at_line(height-1),
self._end(), gtk.FALSE)
if height > self._height :
start = self._buff.get_start_iter()
end = start.copy()
start.forward_line()
self._buff.delete(start, end)
elif len(line) == self._width :
self._buff.insert_with_tags(self._end(), "\n", self._font[fg+bg])
def put (self, char, fg="0", bg="0") :
if char == "\t" :
for i in range(self._tab_size) :
self._put(" ", fg, bg)
elif char == "\r" :
start = self._buff.get_iter_at_line(self._buff.get_line_count())
self._buff.delete(start, self._end())
elif char == "\b" :
start = self._end()
start.backward_char()
self._buff.delete(start, self._end())
elif char == "\0" :
self.clear()
else :
self._put(char, fg, bg)
def clear (self) :
self._blank()
self._set_size = True
self._size()
if True and (__name__ == "__main__") :
import random, bones.words
random.seed()
win = gtk.Window()
def quit (*args) :
gtk.main_quit()
win.connect("delete-event", quit)
red = gtk.gdk.color_parse("red")
win.modify_bg(gtk.STATE_NORMAL, red)
screen = TextScreenGui()
win.add(screen)
win.show_all()
colors = bones.words.hexa_words(16)
chars = [c for c in "good\b\b\b\b\bbye bye world!\rhello world!\n"] \
+ [c for c in "hello world again!\t" * 3 + "\n"] * 8 \
+ [c for c in "hello world!\b\b\b\b\b\b\rbye bye world!\n"]
def update (*args) :
global colors
if len(chars) == 0 :
screen.clear()
return gtk.FALSE
screen.put(chars.pop(0),
fg=colors[random.randint(0, 15)],
bg=colors[random.randint(0, 15)])
return gtk.TRUE
gobject.timeout_add(70, update)
gtk.mainloop()
import threading, sys
import bones.cpu, bones.dev.memory, bones.dev.screen, bones.bus
class Machine (threading.Thread) :
def __init__ (self, view, rom) :
threading.Thread.__init__(self)
self.setDaemon(True)
self.view = view
self.ram = bones.dev.memory.RAM(view.ram)
self.rom = bones.dev.memory.ROM(None, rom)
self.screen = bones.dev.screen.TextScreen(view.screen)
self.bus = bones.bus.Bus(view.bus, self.rom, self.ram, self.screen)
self.cpu = bones.cpu.Cpu(self.bus, view.cpu)
def run (self) :
try :
self.cpu.boot()
while True :
self.cpu.cycle()
except bones.cpu.CpuHalted :
type, value, traceback = sys.exc_info()
self.view.halt(str(value))
except :
self.view.halt()
raise
import threading, Queue, gtk
class SharedVariable :
"Atomic variable"
def __init__ (self, default=None) :
"Init with default value"
self._value = default
self._lock = threading.Lock()
def __call__ (self, value=None) :
"Test and set (if value is not None)"
self._lock.acquire()
result = self._value
if value is not None :
self._value = value
self._lock.release()
return result
def update (self, function) :
self._lock.acquire()
self._value = function(self._value)
self._lock.release()
class SharedCounter (SharedVariable) :
def inc (self, step=1) :
self._lock.acquire()
self._value += step
self._lock.release()
def dec (self, step=1) :
self.inc(-step)
class SharedDict :
"Atomic dictionnary"
def __init__ (self, default={}) :
"Init with default value"
self._dict = dict(default)
self._lock = threading.Lock()
def __getitem__ (self, key) :
self._lock.acquire()
result = self._dict[key]
self._lock.release()
return result
def __setitem__ (self, key, value) :
self._lock.acquire()
self._dict[key] = value
self._lock.release()
def items (self) :
self._lock.acquire()
result = [(key, value) for key, value in self._dict.items()]
self._lock.release()
return result
def keys (self) :
self._lock.acquire()
result = [key for key in self._dict.keys()]
self._lock.release()
return result
def values (self) :
self._lock.acquire()
result = [value for value in self._dict.values()]
self._lock.release()
return result
def update (self, other) :
self._lock.acquire()
self._dict.update(dict(other))
self._lock.release()
def get (self, key, fallback=None) :
self._lock.acquire()
result = self._dict.get(key, fallback)
self._lock.release()
return result
class SharedList :
def __init__ (self, *items) :
self._list = list(items)
self._lock = threading.Lock()
def append (self, item) :
self._lock.acquire()
self._list.append(item)
self._lock.release()
def __iter__ (self) :
self._lock.acquire()
_list = self._list[:]
self._lock.release()
return iter(_list)
def pop (self, index) :
self._lock.acquire()
try :
result = self._list.pop(index)
finally :
self._lock.release()
return result
def __len__ (self) :
self._lock.acquire()
_len = len(self._list)
self._lock.release()
return _len
File mode changed
from bones.view.events import Event
class BusView :
def __init__ (self, queue, gui) :
self.gui = gui
self.queue = queue
def _set_state (self, state, text=None) :
return Event("bus event: " + state,
self.gui.cycle.set_state, state, text)
def _update (self, data, address, command) :
return Event("bus update: data=%s address=%s command=%s"
% (data, address, command),
self.gui.update, data, address, command)
def update (self, data, address, command) :
self.queue.new(self._update(data, address, command))
def reset (self) :
self.queue.new(Event("bus reset", self.gui.reset))
def select (self, device, command) :
self.queue.new(self._set_state("select", "%s: %s"
% (device, command)))
def transmit (self, data, address, command) :
self.queue.new(self._set_state("transmit")
+ self._update(data, address, command))
def finish (self, data, address, command) :
self.queue.new(self._set_state("idle")
+ self._update(data, address, command))
from bones.view.events import Event, CycleEvent
from bones.cpu import RegSet, InterruptVector
class RegView :
def __init__ (self, queue, gui) :
self.gui = gui
self.queue = queue
def update (self, **regs) :
_regs = regs.copy()
reg, val = _regs.popitem()
event = Event("update registers %s" % str(regs),
self.gui.update, reg, val)
for reg, val in _regs.items() :
event += Event("", self.gui.update, reg, val)
self.queue.new(event)
def reset (self) :
pass
class InterruptVectorView :
def __init__ (self, queue, gui) :
self.gui = gui
self.queue = queue
def set_state (self, number, state) :
self.queue.new(Event("set interrupt %s := %s" % (number, str(state)),
self.gui.set_state, number, state))
def set_mask (self, number, state) :
self.queue.new(Event("set mask %s := %s" % (number, str(state)),
self.gui.set_mask, number, state))
def reset_mask (self, mask) :
_mask = mask.copy()
number, state = _mask.popitem()
event = Event("reset mask %s" % str(mask),
self.gui.set_mask, number, state)
for number, state in _mask.items() :
event += Event("", self.gui.set_mask, number, state)
self.queue.new(event)
def reset (self) :
self.queue.new(Event("reset interrupts", self.gui.reset))
class CpuView :
def __init__ (self, queue, gui) :
self.gui = gui
self.queue = queue
def _state (self, state) :
if state is None :
return "inactive"
else :
return str(state)
def boot (self, state) :
self.queue.new(Event("booting: " + self._state(state),
self.gui.boot.set_state, state))
def decode (self, asm) :
self.queue.new(Event("decoded: " + asm,
self.gui.cycle.set_state, "decode.done", asm))
def handler (self, state) :
self.queue.new(Event("handling interrupt: " + self._state(state),
self.gui.handle.set_state, state))
def cycle (self, state) :
if state == "start" :
self.queue.new(CycleEvent())
self.queue.new(Event("cycle: " + self._state(state),
self.gui.cycle.set_state, state))
def execute (self, state) :
self.queue.new(Event("execute: " + self._state(state),
self.gui.cycle.set_state, "execute.done", state))
def tick (self) :
self.queue.new(Event("clock tick",
self.gui.control.tick))
import Queue, time
from bones.threads import SharedVariable, SharedCounter
class EventError (Exception) :
pass
class NoMoreEvent (Exception) :
pass
class Event :
def __init__ (self, text, *args) :
self._do = [list(args)]
self._text = text
def __str__ (self) :
return self._text
def do (self, cursor) :
for spec in self._do :
spec[0](*spec[1:])
return False
def __add__ (self, other) :
result = self.__class__("\n".join([self._text, other._text]))
result._do = self._do[:]
result._do.extend(other._do[:])
return result
class LongEvent (Event) :
def do (self, cursor) :
cursor.wait()
result = Event.do(self, cursor)
cursor.normal()
return result
class CycleEvent (Event) :
def __init__ (self, text="start cycle") :
self._text = text
def do (self, cursor) :
return True
class EventQueue :
def __init__ (self, length=1, debug=False) :
self.can_do = SharedVariable(False)
self._queue = Queue.Queue(length)
self.debug = debug
self._closed = SharedVariable(None)
def new (self, event, block=True) :
self.can_do(True)
while True :
try :
self._queue.put(event, False)
break
except Queue.Full :
time.sleep(0.01)
def do (self, cursor, timeout=0.01) :
closed = self._closed()
if closed is not None :
if self.debug :
print ">>>", closed
raise NoMoreEvent, closed
try :
event = self._queue.get(True, timeout=timeout)
except Queue.Empty :
raise EventError, "no event to do"
if self.debug :
lines = [l.strip() for l in str(event).split("\n")
if len(l.strip()) > 0]
print ">>>", lines.pop(0)
for l in lines :
print "...", l
self.can_do(self._queue.qsize() > 0)
return event.do(cursor)
def close (self, text) :
self.can_do(False)
self._closed(text)
import bones.view.events, bones.view.memory, bones.view.bus, bones.view.cpu
import bones.view.screen
import gtk
class MachineView :
def __init__ (self, gui) :
self.gui = gui
self.queue = bones.view.events.EventQueue()
self.ram = bones.view.memory.MemoryView(self.queue, gui.ram)
self.screen = bones.view.screen.ScreenView(self.queue, gui.dev[1])
self.bus = bones.view.bus.BusView(self.queue, gui.bus)
self.cpu = bones.view.cpu.CpuView(self.queue, gui.cpu)
self.reg = bones.view.cpu.RegView(self.queue, gui.cpu.reg)
self.intr = bones.view.cpu.InterruptVectorView(self.queue,
gui.cpu.intr)
self.cpu.reg = self.reg
self.cpu.intr = self.intr
def halt (self, message=None) :
if message is None :
text = "halt cpu"
else :
text = "halt cpu: " + message
self.queue.close(text)
from bones.view.events import Event, LongEvent
class MemoryView :
def __init__ (self, queue, gui) :
self.gui = gui
self.queue = queue
def update (self, address, value) :
self.queue.new(Event("update memory: [%s] := %s" % (address, value),
self.gui.update, address, value))
def reset (self, data, used) :
self.queue.new(LongEvent("reset memory",
self.gui.reset, data, used))
from bones.view.events import Event
class ScreenView :
def __init__ (self, queue, gui) :
self.gui = gui
self.queue = queue
def clear (self) :
pass
def put (self, char, fg, bg) :
self.queue.new(Event("display char '%s:%s:%s'" % (char, fg, bg),
self.gui.put, char, fg, bg))
import math
def int_to_hexa (value, width=4) :
return (("%%0%ux" % width) % value).upper()
def hexa_to_int (value) :
return int(eval("0x" + value, {}, {}))
_hexa_to_bin = {}
_count = 0
for d1 in ["0", "1"] :
for d2 in ["0", "1"] :
for d3 in ["0", "1"] :
for d4 in ["0", "1"] :
_hexa_to_bin[("%01x" % _count).upper()] = d1+d2+d3+d4
_count += 1
del _count
def hexa_to_bin (word) :
return "".join([_hexa_to_bin[h] for h in word.upper()])
_bin_to_hexa = dict([(value, key) for key, value in _hexa_to_bin.items()])
def bin_to_hexa (bin) :
result = ""
while len(bin) < 16 :
bin = "0" + bin
for i in range(4) :
result += _bin_to_hexa[bin[:4]]
bin = bin[4:]
return result
def hexa_words (count) :
format = "%%0%ux" % int(math.ceil(math.log(count, 16)))
return [(format % i).upper() for i in range(count)]
#!/usr/bin/env python
import pygtk
pygtk.require("2.0")
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
warnings.filterwarnings("ignore", category=RuntimeWarning,
message="tmpnam is a potential security risk to your program")
from bones.gui import editor
editor.MainWindow()
@pythonw -x "%~f0" %* & exit /b
#!/usr/bin/env python
import sys, os, time
if len(sys.argv) == 1 :
rom = [line.strip() for line in sys.stdin]
elif sys.argv[1] == "--fork" :
if os.fork() != 0 :
os._exit(0)
rom = [line.strip() for line in sys.stdin]
elif sys.argv[1] == "--tmpfile" :
rom = [line.strip() for line in open(sys.argv[2])]
os.remove(sys.argv[2])
else :
sys.stderr.write("bones: invalid command line\n")
sys.exit(1)
import warnings
import gtk, gobject
import bones.gui.control, bones.view.machine, bones.machine
from bones.view.events import EventError, NoMoreEvent
class Bones :
def __init__ (self, rom) :
self.rom = rom
self.gui = bones.gui.control.BonesWindow(self.rom)
self.view = bones.view.machine.MachineView(self.gui)
self.machine = bones.machine.Machine(self.view, self.rom)
self.gui.main.irq.assign("0", "boot")
self.gui.main.irq.assign("1", "device error")
self.gui.main.irq.assign("2", "clock")
self.gui.cpu.control.reset.connect("clicked", self.reset)
self.gui.cpu.control.clock.connect("clicked", self.clock)
self.gui.control.next.connect("clicked", self.next)
self.gui.control.cycle.connect("clicked", self.cycle)
self._can_do = False
self._autorun = False
self._id = None
gobject.timeout_add(100, self.update)
self.gui.control.run.connect("clicked", self.start_run)
self.gui.control.stop.connect("clicked", self.stop_run)
def reset (self, *args) :
self.gui.cpu.control.reset.set_sensitive(gtk.FALSE)
self.machine.cpu.reset()
def clock (self, *args) :
self.machine.cpu.clock()
def control_set_sensitive (self, sensitive=gtk.TRUE) :
for button in [self.gui.control.next,
self.gui.control.cycle,
self.gui.control.run] :
button.set_sensitive(sensitive)
def update (self, *args) :
time.sleep(0.01)
if self.view.queue.can_do() and not self._autorun :
self.control_set_sensitive(gtk.TRUE)
else :
self.control_set_sensitive(gtk.FALSE)
return gtk.TRUE
def start_run (self, *args) :
self._autorun = True
self.control_set_sensitive(gtk.FALSE)
self.gui.control.stop.set_sensitive(gtk.TRUE)
self.gui.control.run.set_sensitive(gtk.FALSE)
self.do_run()
def _remove_id (self) :
try :
gobject.source_remove(self._id)
except :
pass
def do_run (self, *args) :
try :
self.do()
speed = (101 - int(self.gui.control.speed.get_value())) * 10
self._id = gobject.timeout_add(speed, self.do_run)
except NoMoreEvent :
self._remove_id()
return gtk.FALSE
def stop_run (self, *args) :
self._autorun = False
self.gui.control.stop.set_sensitive(gtk.FALSE)
self.gui.control.run.set_sensitive(gtk.TRUE)
self._remove_id()
self.update()
def do (self, cycle=False) :
while True :
try :
if cycle == self.view.queue.do(self.gui.cursor) :
break
except EventError :
time.sleep(0.01)
except NoMoreEvent :
self.gui.main.set_sensitive(gtk.FALSE)
self.gui.control.disable()
if self._autorun :
raise
else :
return
def next (self, *args) :
self.do()
self.update()
def cycle (self, *args) :
self.gui.cursor.wait()
self.do(cycle=True)
self.gui.cursor.normal()
self.update()
def start (self) :
self.machine.start()
self.gui.show_all()
self.update()
self.gui.run()
if __name__ == "__main__" :
warnings.filterwarnings("ignore", category=DeprecationWarning)
bones = Bones(rom)
bones.view.queue.debug = True
print "=" * 29, "starting", "=" * 29
bones.start()
#!/usr/bin/env python
import sys, os, time
if len(sys.argv) == 1 :
rom = [line.strip() for line in sys.stdin]
elif sys.argv[1] == "--fork" :
if os.fork() != 0 :
os._exit(0)
rom = [line.strip() for line in sys.stdin]
elif sys.argv[1] == "--tmpfile" :
rom = [line.strip() for line in open(sys.argv[2])]
os.remove(sys.argv[2])
else :
sys.stderr.write("bones: invalid command line\n")
sys.exit(1)
import warnings
import gtk, gobject
import bones.gui.control, bones.view.machine, bones.machine
from bones.view.events import EventError, NoMoreEvent
class Bones :
def __init__ (self, rom) :
self.rom = rom
self.gui = bones.gui.control.BonesWindow(self.rom)
self.view = bones.view.machine.MachineView(self.gui)
self.machine = bones.machine.Machine(self.view, self.rom)
self.gui.main.irq.assign("0", "boot")
self.gui.main.irq.assign("1", "device error")
self.gui.main.irq.assign("2", "clock")
self.gui.cpu.control.reset.connect("clicked", self.reset)
self.gui.cpu.control.clock.connect("clicked", self.clock)
self.gui.control.next.connect("clicked", self.next)
self.gui.control.cycle.connect("clicked", self.cycle)
self._can_do = False
self._autorun = False
self._id = None
gobject.timeout_add(100, self.update)
self.gui.control.run.connect("clicked", self.start_run)
self.gui.control.stop.connect("clicked", self.stop_run)
def reset (self, *args) :
self.gui.cpu.control.reset.set_sensitive(gtk.FALSE)
self.machine.cpu.reset()
def clock (self, *args) :
self.machine.cpu.clock()
def control_set_sensitive (self, sensitive=gtk.TRUE) :
for button in [self.gui.control.next,
self.gui.control.cycle,
self.gui.control.run] :
button.set_sensitive(sensitive)
def update (self, *args) :
time.sleep(0.01)
if self.view.queue.can_do() and not self._autorun :
self.control_set_sensitive(gtk.TRUE)
else :
self.control_set_sensitive(gtk.FALSE)
return gtk.TRUE
def start_run (self, *args) :
self._autorun = True
self.control_set_sensitive(gtk.FALSE)
self.gui.control.stop.set_sensitive(gtk.TRUE)
self.gui.control.run.set_sensitive(gtk.FALSE)
self.do_run()
def _remove_id (self) :
try :
gobject.source_remove(self._id)
except :
pass
def do_run (self, *args) :
try :
self.do()
speed = (101 - int(self.gui.control.speed.get_value())) * 10
self._id = gobject.timeout_add(speed, self.do_run)
except NoMoreEvent :
self._remove_id()
return gtk.FALSE
def stop_run (self, *args) :
self._autorun = False
self.gui.control.stop.set_sensitive(gtk.FALSE)
self.gui.control.run.set_sensitive(gtk.TRUE)
self._remove_id()
self.update()
def do (self, cycle=False) :
while True :
try :
if cycle == self.view.queue.do(self.gui.cursor) :
break
except EventError :
time.sleep(0.01)
except NoMoreEvent :
self.gui.main.set_sensitive(gtk.FALSE)
self.gui.control.disable()
if self._autorun :
raise
else :
return
def next (self, *args) :
self.do()
self.update()
def cycle (self, *args) :
self.gui.cursor.wait()
self.do(cycle=True)
self.gui.cursor.normal()
self.update()
def start (self) :
self.machine.start()
self.gui.show_all()
self.update()
self.gui.run()
if __name__ == "__main__" :
warnings.filterwarnings("ignore", category=DeprecationWarning)
bones = Bones(rom)
bones.view.queue.debug = True
print "=" * 29, "starting", "=" * 29
bones.start()
No preview for this file type
\documentclass[a4paper,runningheads]{llncs}
\usepackage{pdf}
\usepackage{miage}
\def\hexa #1{\relax\ifmmode\mathtt{\##1}\else\texttt{\##1}\fi}
\def\asm{\begingroup\obeyspaces\ASM}
\def\ASM #1{\relax\ifmmode\mathtt{#1}\else\texttt{#1}\fi\endgroup}
\parindent=0pt
\parskip=\medskipamount
\pagestyle{empty}
\begin{document}
%%
%%
\begin{abstract}
Ce document rappelle les principales informations concernant la
machine virtuelle Bones. Il est autorisé pour les contrôles et examens
à la condition impérative qu'il ne porte aucune marque ou annotation.
\end{abstract}
%%
%%
La machine comporte un processeur, un bus, une ROM contenant le BIOS
et une RAM. Tous les mots font 16~bits et la capacité des mémoires est
de $2^{16}$ mots.\note{La notation \hexa{} indique l'hexadécimal, par
exemple, \hexa{F} est le nombre~15.}
Le processeur comporte les 16 registres suivants (donnés avec leurs
numéros)~: \hexa{0} à \hexa{9}~: \asm{R0} à \asm{R9}, registres de
travail~; \hexa{A}~: \asm{RF}, registre «Flag»~; \hexa{B}~: \asm{RI},
registre d'instructions~; \hexa{C}~: \asm{RD}, registre de données~;
\hexa{D}~: \asm{RA}, registre d'adresses~; \hexa{E}~: \asm{IP},
compteur ordinal ({\it instruction pointer\/})~; \hexa{F}~: \asm{SP},
pointeur de pile ({\it stack pointer\/}).
Le BIOS est organisé de la façon suivante~: \hexa{0000} à
\hexa{000F}~: table d'interruptions~; \hexa{0010}~: compteur
d'horloge~; \hexa{0011} à \hexa{0100}~: pile. La pile comporte 15
niveaux dont chacun permet de stocker le masque d'interruptions et
tous les registres sauf \asm{SP}.
Les instructions du processeur sont codées sur 16~bits, soit 4
chiffres hexadécimaux \hexa{iixy}\hexa{ii} est le code de
l'instruction sur 8~bits, \hexa{x} est le premier argument et \hexa{y}
est le second argument (tous les deux sur 4~bits). Les différentes
instructions sont les suivantes, on donne le code, le nom, les
arguments (\asm{R} ou \asm{R'} pour un registre, \asm{N} pour un
chiffre hexadécimal et \asm{-} pour noter l'absence d'un argument) et
une description~:
%
\begin{center}
\begin{tabular}{l@{\qquad}l}
\asm{\#00: HALT - -} & stoppe le CPU et la machine \\
\asm{\#01: CLI - -} & initialise le vecteur d'interruption et son
masque \\
\asm{\#02: INTR N -} & lève l'interruption \asm{N} \\
\asm{\#03: IRET - -} & termine une interruption \\
\asm{\#04: BUS R -} & active le bus, \asm{R} sert à communiquer
avec le bus de commande \\
\asm{\#05: JMP R -} & saute à l'adresse stockée dans \asm{R} \\
\asm{\#06: JZ R R'} & saute à l'adresse stockée dans \asm{R'} si
$\asm{R}=0$ \\
\\
\asm{\#10: RST R -} & initialise \asm{R} à zéro \\
\asm{\#11: CP R R'} & affecte à \asm{R'} le contenu de \asm{R} \\
\asm{\#12: SET R -} & affecte à \asm{R} le mot suivant l'instruction \\
\asm{\#13: LD R R'} & affecte à \asm{R} le mot situé en RAM à
l'adresse indiquée par \asm{R'} \\
\asm{\#14: ST R R'} & sauve le contenu de \asm{R} en RAM à l'adresse
indiquée par \asm{R'} \\
\\
\asm{\#20: ADD R R'} & affecte à \asm{R} la somme $\asm{R} + \asm{R'}$
en positionnant \asm{RF} \\
\asm{\#21: SUB R R'} & affecte à \asm{R} la différence $\asm{R} -
\asm{R'}$ en positionnant \asm{RF} \\
\asm{\#22: MUL R R'} & affecte à \asm{R} le produit $\asm{R} \times
\asm{R'}$ en positionnant \asm{RF} \\
\asm{\#23: DIV R R'} & affecte à \asm{R} le quotient $\asm{R} /
\asm{R'}$ en positionnant \asm{RF} \\
\asm{\#24: MOD R R'} & affecte à \asm{R} le reste de la division
$\asm{R} / \asm{R'}$ en positionnant \asm{RF} \\
\asm{\#25: INC R -} & incrémente \asm{R} en positionnant \asm{RF} \\
\asm{\#26: DEC R -} & décrémente \asm{R} en positionnant \asm{RF} \\
\\
\asm{\#30: AND R R'} & affecte à \asm{R} le «et» binaire $\asm{R} \land
\asm{R'}$ \\
\asm{\#31: OR R R'} & affecte à \asm{R} le «ou» binaire $\asm{R} \lor
\asm{R'}$ \\
\asm{\#32: XOR R R'} & affecte à \asm{R} le «ou exclusif» binaire
$\asm{R} \oplus \asm{R'}$ \\
\asm{\#33: NOT R -} & affecte à \asm{R} le «non» binaire $\lnot
\asm{R}$ \\
\\
\asm{\#40: EQ R R'} & positionne \asm{RF} à \hexa{0001} si $\asm{R} =
\asm{R'}$ et à \hexa{0000} sinon \\
\asm{\#41: GEQ R R'} & positionne \asm{RF} à \hexa{0001} si $\asm{R}
\geq \asm{R'}$ et à \hexa{0000} sinon \\
\asm{\#42: LEQ R R'} & positionne \asm{RF} à \hexa{0001} si $\asm{R}
\leq \asm{R'}$ et à \hexa{0000} sinon
\end{tabular}
\end{center}
\end{document}