| Code: Data serialization:
T0 - - - CARRY CARRY CARRY T1 PC0 STK0 ROMD0 REGx0 RAM0 ROMD0 phi2: /RD high if needed T2 PC1 STK1 ROMD1 REGx1 RAM1 ROMD1 ALU0 T3 PC2 STK2 ROMD2 REGx2 RAM2 ROMD2 ALU1 T4 PC3 STK3 ROMD3 REGx3 RAM3 ROMD3 ALU2 T5 PC4 STK4 ROMD4 REGx4 RAM4 ROMD4 ALU3 T6 PC5 STK5 ROMD5 REGx5 RAM5 ROMD5 ALU4 T7 PC6 STK6 ROMD6 REGx6 RAM6 ROMD6 ALU5 T8 PC7 STK7 ROMD7 REGx7 RAM7 ROMD7 ALU6 T9 PC8 STK8 ROMD8 CARRY CARRY CARRY ALU7 T10 PC9 STK9 ROMD9 - - - update RAM latch, if needed T11 PC10 STK10 ROMD10 - - - phi1: /WR low if needed T12 PC11 STK11 ROMD11 - - - phi2: /WR high if needed T13 - - - - - T14 - - - - - T15 - - - - - - phi1: /RD low if needed
PC operations:
ph0 ph1 ph2 0 stk 2->3 stk 1->2 (pushing) 1 PC->stk 1 latch PC0 2 latch PC1 3 latch PC2 4 latch PC3 5 latch PC4 6 latch PC5 7 latch PC6 8 latch PC7 9 latch PC8 10 latch PC9 11 latch PC10 12 latch PC11, stk 1->PC (popping, for 4 bank bits) 13 stk 2->1 stk 3->2 (popping) 14 clear datalat load datalat 15
The ROM wait state generator is triggered on phi1 of T13. The RAM wait state generator is triggered on phi1 of T15.
running the state stuff: ------------------------
ph0 latch state counter ph1 update state counter, reset run flipflop (gated with state 15 for full cycle running) ph2 reset S/R flipflop that gates johnson counter
instruction set key: -------------------- n = 8 bit RAM address w = 8 bit immediate value a = 12 bit address p = 8 bit IO port address x = don't care bits
(n) = the memory at RAM address n N.M = bit M of N c = carry flag | = logical OR & = logical AND ^ = logical XOR << shift left >> shift right
Normal ALU instructions: ------------------------
There are 6 kinds of normal ALU instructions. All work the same, except the next instruction can be skipped depending on the state of the zero flag.
1111 = ALU, store in F, skip if Z clear 1110 = ALU, store in A, skip if Z clear
The ALU operation is performed, then the next instruction is skipped if the zero flag is clear.
---
1101 = ALU, store in F, skip if Z set 1100 = ALU, store in A, skip if Z set
The ALU operation is performed, then the next instruction is skipped if the zero flag is set.
---
1011 = ALU, store in F 1010 = ALU, store in A
The ALU operation is perfomed and the next instruction is never skipped.
???0 0000 nnnn nnnn LDA n a <- (n) ???1 0000 nnnn nnnn STA n (n) <- a ???0 0001 nnnn nnnn XOR n a <- a ^ (n) ???1 0001 nnnn nnnn XOR n,m (n) <- a ^ (n) ???0 0010 nnnn nnnn AND n a <- a & (n) ???1 0010 nnnn nnnn AND n,m (n) <- a & (n) ???0 0011 nnnn nnnn OR n a <- a | (n) ???1 0011 nnnn nnnn OR n,m (n) <- a | (n)
???0 0100 nnnn nnnn RL n a <- (n) << 1; c <- (n).7 ???1 0100 nnnn nnnn RL n,m (n) <- (n) << 1; c <- (n).7 ???0 0101 nnnn nnnn RLC n a <- (n) << 1 | c; c <- (n).7 ???1 0101 nnnn nnnn RLC n,m (n) <- (n) << 1 | c; c <- (n).7 ???0 0110 nnnn nnnn RR n a <- (n) >> 1; c <- (n).0 ???1 0110 nnnn nnnn RR n,m (n) <- (n) >> 1; c <- (n).0 ???0 0111 nnnn nnnn RRC n a <- (n) >> 1 | (c << 7); c <- (n).0 ???1 0111 nnnn nnnn RRC n,m (n) <- (n) >> 1 | (c << 7); c <- (n).0
???0 1000 nnnn nnnn ADD n a <- a + (n); c = carry ???1 1000 nnnn nnnn ADD n,m (n) <- a + (n); c = carry ???0 1001 nnnn nnnn SUB n a <- a - (n); c = carry ???1 1001 nnnn nnnn SUB n,m (n) <- a - (n); c = carry ???0 1010 nnnn nnnn DEC n a <- (n) - 1 ???1 1010 nnnn nnnn DEC n,m (n) <- (n) - 1 ???0 1011 nnnn nnnn INC n a <- (n) + 1 ???1 1011 nnnn nnnn INC n,m (n) <- (n) + 1
???0 1100 nnnn nnnn ADC n a <- a + (n) + c; c = carry ???1 1100 nnnn nnnn ADC n,m (n) <- a + (n) + c; c = carry ???0 1101 nnnn nnnn SBC n a <- a - (n) + c; c = carry ???1 1101 nnnn nnnn SBC n,m (n) <- a - (n) + c; c = carry ???0 1110 nnnn nnnn SETA a <- 0ffh ???1 1110 nnnn nnnn SET n (n) <- 0ffh ???0 1111 nnnn nnnn CLRA a <- 000h ???1 1111 nnnn nnnn CLR n,m (n) <- 000h
Immediate ALU instructions: ---------------------------
These instructions perform a function with the literal value, vs. a value pulled from memory.
Depending on bit 12, a RET function is performed or not. If bit 12 is cleared, then a return is performed along with the ALU function. This makes it useful to perform table lookups, index a table of offsets to add, etc. when combined with the OFFSET instruction (see below).
The last 4 of these immediate instructions are specialized.
RET and RTI do not affect flags, or change the accumulator. RET pops the PC off the top of stack and then adds 1 to it, while RTI does NOT add 1. See the CALL instruction for the reasoning behind this.
1001 = ALU, immediate 1000 = ALU, immediate, return
If the instruction returns, R is added to it like so:
LDAR #012h XORR #034h
100? 0000 wwww wwww LDA #w a <- w 100? 0001 wwww wwww XOR #w a <- a ^ w 100? 0010 wwww wwww AND #w a <- a & w 100? 0011 wwww wwww OR #w a <- a | w 100? 0100 wwww wwww RL #w a <- w << 1 100? 0101 wwww wwww RLC #w a <- w << 1 | c; c <- w.7 100? 0110 wwww wwww RR #w a <- w >> 1 | c << 7 100? 0111 wwww wwww RRC #w a <- w >> 1 | c << 7; c <- w.0 100? 1000 wwww wwww ADD #w a <- a + w 100? 1001 wwww wwww SUB #w a <- a - w 100? 1010 wwww wwww DEC #w a <- w - 1 100? 1011 wwww wwww INC #w a <- w + 1 100? 1100 wwww wwww ADC #w a <- a + w; c = carry 100? 1101 wwww wwww SBC #w a <- a - w + c; c = carry
1000 1110 xxxx xxxx RET PC <- (top of stack) + 1
RET returns from a CALL instruction. It moves the top of stack back into the program counter, then increments it. This is because the following operations take place during a CALL:
0100h CALL 0200h
First, the PC is pushed onto the stack (0100h) then address 0200h is loaded into the PC.
Next, when the RET instruction is executed, it loads the top of stack back into the PC. The value 0100h is stored on the stack, so 0100h would be loaded back into the PC. This would cause the CALL instruction to be executed again. Thus, 1 is added when it's popped so it points to 0101h, which is the next instruction to execute.
1000 1111 xxxx xxxx RTI PC <- (top of stack)
This instruction performs similar to the RET, except it DOES NOT add 1 to the PC when the top of stack is popped. This is due to how interrupts work: Interrupts are performed by instruction substitution. If the following occurs...
0100h LDA #012h <interrupt> 0101h STA 089h
First, the LDA is executed. The interrupt input is tested at the end of the LDA, and if an interrupt is pending, it will substitute a JSR 008h instruction into the opcode latch, in place of the STA.
This causes the CPU to execute JSR 008h instead of STA, which pushes the PC first, then JSR's to 008h. When the interrupt finishes, execution should proceed back at 0101h because the STA never got executed. Thus, 1 is NOT added to the PC so that the STA gets executed. Otherwise, execution would pick up at 0102h which skips the STA.
---
1001 1110 pppp pppp OUT (p) port(p) <- a 1001 1111 pppp pppp IN (p) a <- port(p)
Input or output data to IO port p.
--- 0111 aaaa aaaa aaaa CALL a (top of stack) <- PC, PC <- a
The PC is first pushed to the top of stack, then it is loaded with address a.
---
0110 aaaa aaaa aaaa JMP a PC <- a
The PC is loaded with address a.
---
0101 -bbb nnnn nnnn BTFSC x,bit if (n).b is clear, skip next instruction 0100 -bbb nnnn nnnn BTFSS x,bit if (n).b is set, skip next instruction
The memory location n is read, and then one of the 8 bits is tested. If the bit is set or clear (depending on if BTFSC or BTFSS is run) will determine if the next instruction is skipped.
A typical loop would look something like this:
loop: inc counter btfss status,z jmp loop
inc counter will increment the variable "counter", which sets the Z and N flags depending on the result of the increment. The flags are stored in the status register, which is mapped into RAM space.
btfss status,z is testing the zero flag. If it's set, the jmp will be skipped over, breaking the loop. If Z is NOT set, the jmp is executed and counter is incremented again.
jmp loop will continue the loop until it is skipped over by the btfss instruction.
---
0011 -bbb nnnn nnnn BSF x,bit set (n).b 0010 -bbb nnnn nnnn BCF x,bit clear (n).b
These two instructions set or clear a single bit of memory in RAM.
---
0001 001x nnnn nnnn OFFSET x PC <- PC + (n) + 1
The offset instruction is how table lookups are performed. The value of memory pointed to by n will be added to the program counter, unsigned. This allows a lookup table that is up to 256 bytes deep.
The method works like this:
<code> CALL tablelut <more code> ...
tablelut: OFFSET address LDAR #12h LDAR #34h LDAR #56h LDAR #78h
if (address) is equal to 00h, nothing is added, and execution falls through to the LDAR #12h instruction. If (address) equals 01h, then 1 is added to the PC, and then PC is incremented. This then points PC to the LDAR #34h instruction, and so on.
---
All other instructions act as NOPs. 0000 0000 0000 0000 is the prototypical NOP.
Memory accessing: -----------------
The 8 bit address space looks like this:
00-EF : general purpose RAM F0-F3 : not used at the moment (for inputs though) F4 : accumulator F5 : status register (flags) F6 : index data port 0 F7 : index data port 1 F8-F9 : not used at the moment (for more write registers) FA : ROM bank FB : general RAM bank # (bits 0-3) and interrupt enable (bit 7) FC : index register 0 FD : index bank 0 FE : index register 1 FF : index bank 1
Addresses 00-EFh simply map to RAM bytes. The 4 bit bank value is stored at address FBh. So, to read a byte of memory located at 0123h in RAM, the following is used:
LDA #01h ;bank 1 STA 0FBh ;(labelled "genbank") LDA 023h ;data at addres 0123h
Addresses F0-FF always SET the 4 bank bits when accessed, so that the value is always written to FF0-FFFh (in RAM space). This prevents overwriting F0-FF in the bank that is currently selected.
Addresses at F0-F7 are typically input only, and cannot be written to with the exception of the accumulator (F4h) and the status register (F5h).
The exception to this is addresses F6 and F7, which are the two index data ports.
Index registers:
There are two index registers, IX0 and IX1. These are 8 bit registers with 4 bit bank select registers that can be used to access a byte of RAM indirectly. The value on IX0 and its associated bank register is used as the address when location F6 is either read or written, likewise IX1 and its associated bank register is used as the address when location F7 is read or written.
The two index registers are provided to allow for copying of data, and for processing of data in a linear fashion.
| |