class KeyboardTest(BaseDCPU16Test, unittest.TestCase): def setUp(self): self.device = Keyboard() self.cpu = DCPU16([self.device]) def test_multiple_interrupts(self): self.cpu.ram[:5] = [ # ias, :handler 0x7d40, 0x0007, # turn on hardware interrupts with message "0xbeef" # set a, 3 / set b, 0xbeef / hwi, 0 0x9001, 0x7c21, 0xbeef, 0x8640, # sub pc, 1 0x8b83, # handler: # get the keypress from the device: set a, 1 / hwi, 0 0x8801, 0x8640, # rfi 0 0x8560 ] # cycle 6 times for _ in xrange(6): self.cpu.cycle() # feed the keyboard "A" self.device.register_keypress(ord("A")) # cycle some more for _ in xrange(3): self.cpu.cycle() # make sure we got a message. self.assertRegister("C", ord("A")) # make the device interrupt again self.device.register_keypress(ord("B")) for _ in xrange(3): self.cpu.cycle() self.assertRegister("C", ord("B"))
def __init__(self, code): self.keyboard = Keyboard() self.display = LEM1802(self.change_font, self.change_letter, self.change_palette) # things that have changed since we last talked to the client. self.letters_changed = {} # start out by passing all of the font self.chars_changed = dict(enumerate(char_to_bitmap(*t) for t in # group them into twos and call char_to_bitmap on each pair zip(*[iter(self.display.font)]*2))) self.border_color = None self.errors = [] # intialize the cpu self.cpu = DCPU16([self.keyboard, self.display]) # read the code from the factory to the RAM self.cpu.ram[:len(code)] = code
class DCPU16Protocol(protocol.Protocol): cycle_counter = 0 def __init__(self, code): self.keyboard = Keyboard() self.display = LEM1802(self.change_font, self.change_letter, self.change_palette) # things that have changed since we last talked to the client. self.letters_changed = {} # start out by passing all of the font self.chars_changed = dict(enumerate(char_to_bitmap(*t) for t in # group them into twos and call char_to_bitmap on each pair zip(*[iter(self.display.font)]*2))) self.border_color = None self.errors = [] # intialize the cpu self.cpu = DCPU16([self.keyboard, self.display]) # read the code from the factory to the RAM self.cpu.ram[:len(code)] = code def change_palette(self, index, value): #TODO: change the palette -- not sure how this will work. pass def change_font(self, index, value): #TODO: change a font character. pass def change_border(self, index, value): #TODO: format the border color as an html/css hex color. pass def change_letter(self, index, foreground, background, blink, char): "This is called whenever a cell of vram is changed." x, y = divmod(index, 32) self.letters_changed[x, y] = { "x": x, "y": y, "char": char, "blink": blink, # format the background and foreground tuples as html/css colors. "foreground": "#%03x" % self.display.palette[foreground], "background": "#%03x" % self.display.palette[background], } def dataReceived(self, data): # get the keypresses and the number of cycles from the frontend keypresses, count = json.loads(data) for k in keypresses: # hand these to the keyboard self.keyboard.register_keypress(k) try: # cycle as many times as we're supposed to, for _ in xrange(count): self.cpu.cycle() # if we get any errors, let the frontend know. except Exception as e: self.errors.append(str(e)) raise # and then pass everything to the frontend. self.write_changes() def write_changes(self): "Write the changes to the websockets client and reset." changes = { # None if there's no new background color, otherwise a color. "background": self.border_color, # the cells that have been changed since last time "cells": self.letters_changed.values(), # the characters (fonts) that have been changed "characters": self.chars_changed, # any errors we've encountered "errors": self.errors, # whether the frontend should stop. "halt": False, } # reset everything self.transport.write(json.dumps(changes)) self.letters_changed = {} self.chars_changed = {} self.border_color = None self.errors = []
def setUp(self): self.device = Keyboard() self.cpu = DCPU16([self.device])