# TR-8 **Important**: this is a work in progress with pre-alpha quality. Not all the information in this document is final, complete or even accurate. 8-bit fantasy console inspired by MIPS, Z80 and 6502 real world CPUs. ## Specs ``` Display: 128 x 128 pixels 16 colors (from palette of 32) Memory: 64K CPU: TR-8, 8M VM instr/sec Sound: TBD ``` Other features: * programable in ASM * TR-8 CPU - 16-bit registers: stack pointer (SP) and program counter (PC) - 8-bit registers: 4 general purpose registers (a, b, x, y), flags refister (F) * frame interrupt (60Hz) and external IO interrupt * port based IO Memory map: ``` 0x0000 program (48896 bytes) 0xbf00 frame buffer (16K) 0xff00 frame interrupt vector 0xff02 IO interrupt vector 0xff04 stack (251 bytes) 0xffff ``` ## How to build It requires SDL2 and SDL_Mixer. On Linux install a C compiler and the development packages for the requirements. Example on Debian/Ubuntu using `sudo`: sudo apt install build-essential libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev Then run `make`. This will result in two binaries: - *tr8as*: the TR8 assembler - *tr8vm*: the TR8 VM that can run `tr8` files You can then compile and run the example with `make example`. ## Detailed specs ### Ports | Port | Type | Result | | --- | --- | --- | | 0xe0 to 0xef | write | Color select | | 0xf0 | read | Status of the controller 1 | | 0xf1 | read | Status of the controller 2 | ### Controller The controller support d-pad with 4 directions, 2 action buttons, select and start. Read the port `0xf0` for the 8 1-bit flags reporting the state of the controller 1, and `0xf1` for controller 2. ``` 76543210 |||||||\ a (fire 1) ||||||\ b (fire 2) |||||\ d-pad up ||||\ d-pad down |||\ d-pad left ||\ d-pad right |\ select \ start ``` ### Palette Ports from `0xe0` to `0xef` can be used to select the colors to use in the 16 color palette from the 32 available. TODO: palette colours ### Instructions All the instructions are 16-bit, with the exception of `JMP addr` and `CALL addr` that use an extra 16-bit parameter for "addr". All the instructions take the same time to run, and being 8 MIPS it can fit `133333` instructions in a frame (at 60Hz). There are no 16-bit registers, but they can be implemented with 2 registers, and that is supported in some addressing modes with `[r1:r2]`. For example: ```asm ; fill with color 15 ld a, 15 push a call fill pop a ; halt the CPU sif halt ; ; void fill(uint8_t color) ; ; fill frame-buffer with a color ; fill: ; grab the color from the stack ld b, [sp + 2] ; 64 * 256 is 16K ld y, 64 ; a:x is our 16-bit register ld a, 0xbf ld x, 0 fill_loop: ld [a : x], b inc x bno jmp fill_loop ; x overfows, so we increment a ; and decrement y (one 256 block done) inc a dec y bnz jmp fill_loop ret ``` Arithmetic operations on the "16-bit" can be performed easily using branching instructions: ```asm ; inc a:x inc x ; if x overflows we need to increase a bo inc a ``` #### Directives .org addr Set the address to that value. By default the starting address is `0x0000`. .db imm [, imm] Literal byte. Label can be used with `<` prefix for the low byte of the address and `>`for the high byte. .dw imm [, imm] Literal word. #### Load and Store LD r1, r2 Load the value of r2 in r1. LD r1, imm Load the immediate value in r1. LD [r1:r2], r3 Load the value of r3 in the memory address provided by r1:r2. LD r3, [r1:r2] Load into r3 the value in the memory address provided by r1:r2. LD [SP + imm], r1 Load r1 into the stack on top address plus the immediate value. LD r1, [SP + imm] Load into r1 the stack value on top address plus the immediate value. #### Stack PUSH r1 Save the value of r1 on the top of the stack. POP r1 Restore the value of r1 by popping it from the top of the stack. PUSH F Save the flags in the stack. POP F Restore the flags from the top of the stack. XSP r1 Exchange the high byte of the stack pointer by the value in r1. #### Logical AND r1, r2 Logical AND between r1 and r2, storing the result in r1. Affected flags: ZF, SF AND r1, imm Logical AND between r1 and immediate value, storing the result in r1. Affected flags: ZF, SF OR r1, r2 Logical OR between r1 and r2, storing the result in r1. Affected flags: ZF, SF OR r1, imm Logical OR between r1 and immediate value, storing the result in r1. Affected flags: ZF, SF XOR r1, r2 Logical exclusive OR between r1 and r2, storing the result in r1. Affected flags: ZF, SF XOR r1, imm Logical exclusive OR between r1 and immediate value, storing the result in r1. Affected flags: ZF, SF #### Arithmetic INC r1 Incremet r1. Affected flags: ZF, CF, OF, SF DEC r1 Decrement r1. Affected flags: ZF, CF, OF, SF ADD r1, r2 Add r1 and r2, storing the result in r1. Affected flags: ZF, CF, OF, SF ADD r1, imm Add r1 and the immediate value, storing the result in r1. Affected flags: ZF, CF, OF, SF SUB r1, r2 Subtract r2 to r1, storing the result in r1. Affected flags: ZF, CF, OF, SF SUB r1, imm Subtract the immediate value to r1, storing the result in r1. Affected flags: ZF, CF, OF, SF CMP r1, r2 Perform a SUB of r1 minus r2, without storing the result and only updating the flags. Affected flags: ZF, CF, OF, SF CMP r1, imm Perform a SUB of r1 minus the immediate value without storing the result and only updating the flags. Affected flags: ZF, CF, OF, SF #### Bit Operations SHL r1, n Shift r1 n bits to the left (0 to 7), storing the result in r1. Affected flags: ZF, CF, SF SHR r1, n Shift r1 n bits to the right (0 to 7), storing the result in r1. Affected flags: ZF, CF, SF ROL r1, n Rotate r1 n bits to the left (0 to 7), storing the result in r1. Affected flags: ZF, CF, SF ROR r1, n Rotate r1 n bits to the right (0 to 7), storing the result in r1. Affected flags: ZF, CF, SF BIT r1, n Test bit n (0 to 7) or r1, setting ZF if it is set or clearing it otherwise. Affected flags: ZF #### Jump and Call JMP addr Set the PC to the 16-bit address. CALL addr Store the next PC in the stack (16-bit address) and sets te PC to the 16-bit address. CALL [r1:r2] Store the next PC in the stack (16-bit address) and sets te PC to the 16-bit address provided by r1:r2. RET Return from a call by setting PC to the top 16-bit value popped from the stack. #### Branching BZ inst Branch if Zero, will skip the next instruction if ZF is not set. Affected flags: BF BNZ inst Branch if not Zero, will skip the next instruction if ZF flag is set. Affected flags: BF BC inst Branch if Carry, will skip the next instruction if CF flag is not set. Affected flags: BF BNC inst Branch if not Carry, will skip the next instruction if CF flag is set. Affected flags: BF BO inst Branch if Overflow, will skip the next instruction if OF flag is not set. Affected flags: BF BNO inst Branch if not Overflow, will skip the next instruction if OF flag is set. Affected flags: BF BS inst Branch if Sign, will skip the next instruction if SF flag is not set. Affected flags: BF BNS inst Branch if not Sign, will skip the next instruction if SF flag is set. Affected flags: BF BI inst Branch if Interrupt, will skip the next instruction if IF flag is not set. Affected flags: BF BNI inst Branch if not Interrupt, will skip the next instruction if IF flag is set. Affected flags: BF #### IO, flags and Misc HALT Stop the execution until there is frame interrupt. If the interruption flag is set, this will hang the CPU. PORT r1, r2 Write the value of r2 in the port number provided by r1. If there is an output, the value will be stored in r1. NOP No instruction has no effect. SIF Set IF, disabling the interrupt. Affected flags: IF CIF Clear IF, enabling the interrupt. If called in an interrupt handler, it won't have effect. Use IRET instead to return from the interrupt to unset IF. Affected flags: IF CCF Clear carry flag. Affected flags: CF SCF Set carry flag. Affected flags: CF COF Clear overflow flag. Affected flags: OF IRET Return from an interupt handler by setting PC to the top 16-bit value popped from the stack. It enables interrupts by clearing the interrupt flag. Affected flags: IF ### TR8 file format It is a binary file to be run on the TR-8. It doesn't have a header and it will be loaded at `0x0000` address. The execution will start on that address with interruptions disabled (interruption flag set). See the memory map for further information. ## Author and Licence This was made by [Juan J. Martinez](https://www.usebox.net/jjm/about/me/). The code is MIT licensed.