Code covered by the BSD License  

Highlights from
Extended Brookshear Machine emulator and assembler

image thumbnail
from Extended Brookshear Machine emulator and assembler by David Young
Emulator and assembler for a simple computer, a teaching aid for computer science courses.

step(machine)
function machine = step(machine)
%STEP carries out one execution step on a BM
%   MACHINE = STEP(MACHINE) executes the next instruction (that pointed at
%   by the program counter) for the BM MACHINE, and returns the updated
%   machine.

%   Copyright 2008 University of Sussex and David Young

p = machine.pc;
if p > 254
    throw(MException('bmachine:step:endmem', 'End of memory reached'));
end

b1 = machine.memory(p+1);
b2 = machine.memory(p+2);
machine.pc = p + 2;
[op, r, s, t] = decodeInstr(b1, b2);
machine = exec(machine, op, r, s, t);

end


function machine = exec(machine, op, r, s, t)
% Execute an instruction

instrs = {@NOP, @LOADA, @LOADI, @STORE, @MOVE, @ADDI, @ADDF, @ORBITS, ...
    @ANDBITS, @XORBITS, @ROTBITS, @JUMP, @HALT, @LOADR, @STORER, @JUMPR};

i = instrs{op+1};
machine = i(machine, r, s, t);

end


function machine = NOP(machine, r, s, t)
% Non-operation can be useful for padding, but restrict to special bit
% pattern 0FFF so that don't need to save and restore zero locations in
% memory
f = hex2dec('F');
if r ~= f || s ~= f || t ~= f
    throw(MException('bmachine:NOP:badbyte', 'Illegal instruction'));
end
end


function machine = LOADA(machine, r, x, y)
% Load register r with data from address xy
machine.register(r+1) = machine.memory(nibbles2byte(x,y) + 1);
end


function machine = LOADI(machine, r, x, y)
% Load register r with data from instruction
machine.register(r+1) = nibbles2byte(x,y);
end


function machine = STORE(machine, r, x, y)
% Store register r's contents in memory
machine.memory(nibbles2byte(x,y)+1) = machine.register(r+1);
end


function machine = MOVE(machine, unused, r, s)
% Copy register r to register s
if unused
    throw(MException('bmachine:MOVE:badbyte', 'Invalid second byte in MOVE command'));
end
machine.register(s+1) = machine.register(r+1);
end


function machine = ADDI(machine, r, s, t)
% Integer add: sum of contents of s and t to r
reg = machine.register;
machine.register(r+1) = bitand(reg(s+1) + reg(t+1), hex2dec('ff'));
end


function machine = ADDF(machine, r, s, t)
% Float add: sum of contents of s and t to r
reg = machine.register;
machine.register(r+1) = dble2f8(f82dble(reg(s+1)) + f82dble(reg(t+1)));
end


function machine = ORBITS(machine, r, s, t)
% OR of contents of s and t to r
machine.register(r+1) = bitor(machine.register(s+1), machine.register(t+1));
end


function machine = ANDBITS(machine, r, s, t)
% AND of contents of s and t to r
machine.register(r+1) = bitand(machine.register(s+1), machine.register(t+1));
end


function machine = XORBITS(machine, r, s, t)
% AND of contents of s and t to r
machine.register(r+1) = bitxor(machine.register(s+1), machine.register(t+1));
end


function machine = ROTBITS(machine, r, unused, x)
% Rotate bits in register r to right x places
if unused
    throw(MException('bmachine:ROTBITS:badbyte', 'Non-zero third byte in ROTATE instruction'));
end
x = double(x); % Need -x for bitshift
v = machine.register(r+1);
v = bitor(bitshift(v, -x), bitshift(v, 8-x));
machine.register(r+1) = bitand(v, hex2dec('ff'));
end


function machine = JUMP(machine, r, x, y)
% Jump to address xy if register r equal to register 0
if machine.register(1) == machine.register(r+1)
    machine.pc = nibbles2byte(x, y);
end
end


function machine = HALT(machine, a, b, c)
% Halt machine
if a || b || c
    throw(MException('bmachine:HALT:badbyte', 'Non-zero byte in HALT command'));
end
machine.running = false;
end


function machine = LOADR(machine, unused, r, s)
% Load register r's contents from address indicated by register s
if unused
    throw(MException('bmachine:LOADR:badbyte', 'Invalid second byte in LOADR command'));
end
machine.register(r+1) = machine.memory(machine.register(s+1)+1);
end


function machine = STORER(machine, unused, r, s)
% Store register r's contents at address indicated by register s
if unused
    throw(MException('bmachine:STORER:badbyte', 'Invalid second byte in STORER command'));
end
machine.memory(machine.register(s+1)+1) = machine.register(r+1);
end


function machine = JUMPR(machine, r, s, t)
% Jump to address in register t if test of value in register r against
% register 0 succeeds. Test depends on s.
v0 = machine.register(1);
vr = machine.register(r+1);
switch s
    case 0
        ok = vr == v0;
    case 1
        ok = vr ~= v0;
    case 2
        ok = vr >= v0;
    case 3
        ok = vr <= v0;
    case 4
        ok = vr > v0;
    case 5
        ok = vr < v0;
    otherwise
        throw(MException('bmachine:JUMPR:badtest', 'Invalid test in JUMPR command'));
end
if ok
    machine.pc = machine.register(t+1);
end
end

Contact us at files@mathworks.com