The A7-28-D28 is a microcomputer designed with a RISC architecture.
It is 31 by 26 pixels in size (33x35 w/ stock memory module).
Its instruction address bus is seven bits wide (giving it access to 128 bytes of instruction memory at a time), and its data address bus is 28 bits wide (giving it access to 268,435,456 potential bytes of data memory).
Ports:
IAO (7-bit) - Instruction Address Out, this port is located on the right side and outputs requests for instruction memory
DI (28-bit) - Data In, this port is located on the top and is the only inlet for data on the processor
DO (28-bit) - Data Out, used as the value to write for memory writes when connected to a memory module, or simply as Standard Out when wired directly to an output device and is located on the bottom right
DAO (28-bit) - Data Address Out, address used for manipulating memory
Note, if the IAO and DAO ports are wired to different memory spaces, the machine works in a Harvard archetecture. When they are wired to the same memory module (or the same memory space), the machine works in a Von-Neumann archetecture.
Instructions:
Like the A10D28, the A7-28D28 does not have complex instructions. Instead, each bit of an instruction byte directly connects to a specific hardware action. Ex: if an instruction has all the bits set for "LD L,bus", "LD bus,R0", and "LD out,bus", all three of those hardware actions will be done concurrently in the same cycle.
Instruction bit map:
111111111111
BA9876543210FEDCBA9876543210 - Bit#
[-----][-----]|||||||||||[]|LD bus,(NIP) ;P points to next instruction instead of NIP after this
| | ||||||||||||RP ;”Register Pointer”
| | |||||||||||LD bus,r(RP) ;Load the GP register pointed to by RP into the bus
| | ||||||||||LD r(RP),bus ;Load the bus into the GP regsister pointed to by RP
| | |||||||||LD L,bus ;Load the bus into the Logic Register (L)
| | ||||||||Andrl bus,L ;Performs a bitwise AND followed by an RL. Effects the C flag
| | |||||||Xor bus,L
| | ||||||RR bus
| | |||||Set C
| | ||||brc P,NIP ;set next instruction to P if C is reset, and NIP if C is set
| | |||LD out,bus ;can also be written “out bus”
| | ||LD (bus),out
| | |LD bus,(bus) ;P points to next instruction instead of NIP after this
| |NIP ;”Next Instruction Pointer”
|P ;”(General) Pointer”
Internals:
Real Registers: ;Registers that can be directly manipulated
Bus - The internal data bus treated as a register
L - Logic register
R0, R1, R2, R3 - General Purpose registers, can be referred to as RAM
Hard Registers: ;Values asserted by instruction bytes
NIP - Next Instruction Pointer, the address to read the next instruction from (functionally replaces a PC)
P - General pointer used in the "brc" and "LD bus,(P)" instructions
RP - Register Pointer, index of GP register of register-manipulating instructions like "LD bus,r(RP)"
Flags: ;Used for process control
C - "Condition" Flag. Is only manipulated by the "Andrl" instruction and only read by the "BRC" instruction
Example Program:
ADDR|SB| P | NIP | Instruction | Mnemonic -- Add Two Numbers
0000:10 0000001 0000000 10000000000000: LD bus,(bus); //Get number to input
0001:10 0000010 0000000 10000000010000: LD r0,bus; LD bus,(bus); //Save it and get another
0010:10 0000000 0000011 00000000010010: LD r1,bus;
0011:10 0000000 0000100 00000000001000: LD bus,r0;
0100:10 0000000 0000101 00000000101010: LD l,bus; ld bus,r1; @loop;
0101:10 0000000 0000110 00000010000000: Xor bus,l;
0110:10 0000000 0000111 00000000010000: LD r0,bus;
0111:10 0000000 0001000 00001000001010: LD bus,r1; Set c;
1000:10 0000000 0001001 00000001000000: Andrl bus,l;
1001:10 0000000 0001010 00000000010010: LD r1,bus;
1010:10 0001011 0000100 00010000001000: brc loop,i+; ld bus,r1; //loop until fully added
1011:10 0000000 0000000 00100000000000: ld out,bus; jp %0000; //output and start over
Assembler:
Recently, @LBPHacker added support for this machine in his assembler, https://github.com/LBPHacker/tptasm/
In the assembler, the instructionlet mnemonics were changed slightly for compatibility
Instruction changes:
LD bus,(NIP) -> ldi imm
LD bus,r(RP) -> ld r0, ld r1, ld r2, ld r3
LD r(RP),bus -> st r0, st r1, st r2, st r3
LD L,bus -> stl
Andrl bus,L -> andrl
Xor bus,L -> xor
RR bus -> rr
Set c -> setc
brc P,NIP -> brc label, brnc label ; jump to this if c is set, vs. jump to this if c is reset
LD out,bus -> out
LD (bus),out -> bsto
LD bus,(bus) -> ldb
JP NIP -> br ; jump to this unconditionally (except if there's a brc in the group). By default, the assembler sets NIP to the current instruction address plus one, so there is no need to 'jump' to every subsequent instruction.
In tptasm, instructionlets within the same instruction are seperated by pipes ('|') instead of semicolons, as semicolons are designated for comments.
Be aware that tptasm is case sensitive.
Example:
The following is the same demo program written above, but rewritten for tptasm.
start:
ldb
st r0 | ldb
st r1
ld r0
loop:
stl | ld r1
xor
st r0
ld r1 | setc
andrl
st r1
ld r0 | brc loop
out | br start
IAO is on the right side, seven pixels from the bottom.
And DAO is on the bottom of the machine, I believe
@chemlab
LD (bus),out loads the address at bus with the value of out