Work In Progress - Jimmer1/Chip16 GitHub Wiki
Note This document is not meant for use, it is essentially a dumping ground for all documentation that isn't ready for use in context.
Chip16
Motivation
I wrote this virtual machine as a tool to facilitate learning low level programming techniques while having an easy to learn instruction set. I also valued the ability to let students have a look at how the virtual machine converts machine code into computation. It is for this reason that Python was an excellent choice of programming language as its very high level programming paradigm means that the unnecessary details can be abstracted away and this let me focus on the parts of the program that I wanted to draw attention to as opposed to bogging down students in pointer syntax or other clutter.
Using Devices.
A key feature of the Chip16 VM is the ability to use Devices. Devices are modular extensions to the Chip16 architecture which implement additional functionality to enable the user to write more complex programs. This is the basic interface, what each operation does is defined by the device itself.
Any given instance of the Chip16 VM can support a maximum of 16 devices. A number of standard devices are provided. They are as follows: - ConsoleIO Device: A device to allow the programmer to accept user input and output through the terminal. The read operation reads n bytes from the console in the format specified by the format code. The write operation prints the range of bytes to the console in a big endian format in the format specified by the format code. The set pointer operation sets the format code to the value held in rF. The get pointer operation stores the format code in rF. The format code sets i/o to be either textual if it's 0 and hexadecimal if it's 1. The ConsoleIO Device is available by default at index 0. - Memory Extension Device: A device to allow the VM to have access to an extra 64k of memory. - Rom Device: Allows the programmer to read data from the file rom.crm up to a limit of 64k, cannot write to that file. - Floating Point Device: Implements 32 bit floating point arithmetic.
There are 4 opcodes for interacting with Devices:
Upon encountering a 0000 opcode, the program will terminate. This opcode is represented by the HALT mnemonic.
Illegal Opcodes
If an opcode is encountered which isn't does not encode a valid instruction, then an alert is raised. The VM will continue execution as normal but the alert flag is raised.
Explanation
Chip64 Architectural Specification
The architecture is detailed below:
- 16 16-bit registers
- 1 12-bit program counter
- 1 12-bit memory pointer
- 4096 byte address space
- call stack of 12-bit addressses with a depth of a minimum of 16 addresses.
The initial values that all registers and memory bytes take is unspecified, therefore one should not reply on the emulator to zero these data for maximum portability.
Program execution begins from memory address 0, therefore if one wants to place subroutines at the beginning of the address space then the programmer is mandated to make the initial instruction and unconditional jump to the address where your main code begins.
Value Signedness
All register and address space values are unsigned.
Carry and Borrow
In the addition and subtraction instructions, the terms carry and borrow were defined.
Carry is defined as being when two given addition operands give a result that is too large to fit in a register. For example, if I try to evaluate 0xFF + 0xFF in 8-bit arithmetic. then the result given is 0x1FE, which is too large to fit in an 8-bit register. To indicate this to the programmer, a carry flag is set, in this case it is registers[0xF]. And the truncated 8-bit value 0xFE is given as the result of the addition.
Borrow is defined similarly as when two given subtraction operands give a result that is too small to fit in a register. For example, if I try to evaluate 0 - 1 in 8 bit arithmetic. This is outside the range 0 - 0xFF so the value wraps around to the value 0xFF and so this needs to be indicated by a borrow flag.
References
List of functionality
This software exposes the Chip64 object through which the user interacts with the system through the Chip64::execute() function.
Due to Python's object oriententation model, there are a litany of internal implementation methods which are also exposed.
These methods should not be relied upon, nor should any code depend on any undocumented behaviour of the library.
Mathematics - Multiplication
Using The Grid Method
We may employ the grid method, having stored a set of pre-computed results. In base 10, one will have memorised the times tables for numbers smaller than 10, as we work in base-2, we memorise the times tables for numbers strictly smaller than 16. This would lead to a lookup table that is 225 bytes wide, We may reduce this considerably by performing the following optimisations:
- Store only the values for M $x$ N where M $\ge$ N. This reduces the table in size to 120 bytes.
- Remove all entries where N $=$ 1, since this trivially gives the value M. We are now down to 105 bytes.
- Remove the values for which N $=$ 2, since this can be handled by a single add instruction. We are now down to 91 bytes.
- Remove all values for which N $=$ 3, since this can be handled by a shift and add. We are now down to 78 bytes.
As a result of these optimisations, we must be careful about how we access data from the lookup table.
WIP:
grid_mul:
# r0 --> r1*r2
goto code
# manually computed lookup table.
db 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45
db 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
db 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75
db 36, 42, 48, 54, 60, 66, 72, 78, 84, 90
db 49, 56, 63, 70, 77, 84, 91, 98, 105
db 64, 72, 80, 88, 96, 104, 112, 120
db 81, 90, 99, 108, 117, 126, 135
db 100, 110, 120, 130, 140, 150
db 121, 132, 143, 154, 165
db 144, 156, 168, 180
db 169, 182, 195
db 196, 210
db 225
code:
# swap M, N if N >= M
ar r4, r2
sub r4, r1
snec r15, 1
goto swapend
ar r4, r2
ar r2, r1
ar r1, r4
swapend:
# we can safely assume M >= N
snec r2, 1
goto skip1
ar r0, r1
ret
skip1:
snec r2, 2
goto skip2
add r1, r1
ar r0, r1
ret
skip2:
# use lookup table