Visual6502wiki/6507 Decode ROM
The Decode ROMTemplate:Ref is a 130x21 bits ROM in the 6502 that is used to decode the instruction and to control various units of the CPU.
Some basic (maybe partially incorrect) information: http://www.pagetable.com/?p=39
This is a verified correct transcription of the ROM, taken from the Atari 6507 diagram sheets (this ROM differs from the one in the NMOS 6502, as simulated by the [visual6502 simulator]):
100XX1XX 3 X STY XXX100XX 1 3 T3INDYA XXX110XX 1 2 T2ABSY 1100XXXX 3 0 T0CPYINY 100110XX 3 0 T0TYAA 1X0010XX 3 0 T0DEYINY 000000XX 3 5 T5INT 10XXXXXX 2 X LDXSDX XXX1X1XX X 2 T2ANYX XXX000XX 1 2 T2XIND 100010XX 2 0 T0TXAA 110010XX 2 0 T0DEX 1110XXXX 3 0 T0CPXINX 100110XX 2 0 T0TXS 100XXXXX 2 X SDX 101XXXXX 2 0 T0TALDTSX 110010XX 2 1 T1DEX 111010XX 3 1 T1INX 101110XX 2 0 T0TSX 1X0010XX 3 1 T1DEYINY 101XX1XX 3 0 T0LDY1 1010XXXX 3 0 T0LDY2TAY 0XX0X0XX 3 2 CCC 001000XX 3 0 T0JSR 0X0010XX 3 0 T0PSHASHP 011000XX 3 4 T4RTS 0X1010XX 3 3 T3PLAPLPA 010000XX 3 5 T5RTI 011XXXXX 2 X RORRORA 001000XX 3 2 T2JSR 01X011XX 3 X JMPA XXXXXXXX X 2 T2 XXX011XX X 2 T2EXT 01X000XX 3 X RTIRTS XXX000XX 1 4 T4XIND XXXXXXXX X 0 T0A XXXX0XXX X 2 T2NANYABS 010000XX 3 4 T4RTIA 00X000XX 3 4 T4JSRINT 0XX0XXXX 3 3 NAME1:T3_RTI_RTS_JSR_JMP_INT_PULA_PUPL XXX100XX 1 3 T3INDYB XXX000XX 1 3 T3XIND XXX100XX 1 4 T4INDYA XXX100XX 1 2 T2INDY XXX11XXX X 3 T3ABSXYA 0X1010XX 3 X PULAPULP 111XXXXX 2 X INC 010XXXXX 1 0 T0EOR 110XXXXX 1 0 T0CMP 11X0XXXX 3 0 NAME2:T0_CPX_CPY_INX_INY X11XXXXX 1 0 T0ADCSBC 111XXXXX 1 0 T0SBC 001XXXXX 2 X ROLROLA 01X011XX 3 3 T3JMP 000XXXXX 1 0 T0ORA 00XXXXXX 2 X NAME8:ROL_ROLA_ASL_ASLA 100110XX 3 0 T0TYAB 100010XX 2 0 T0TXAB X11XXXXX 1 1 T1ADCSBCA 0XXXXXXX 1 1 NAME7:T1_AND_EOR_OR_ADC 0XX010XX 2 1 NAME4:T1_ASLA_ROLA_LSRA 011010XX 3 0 T0PULA XXX11XXX X 4 T4ABSXYA XXX100XX 1 5 T5INDY 101XXXXX 1 0 T0LDA XXXXXXXX 1 0 T0G1 001XXXXX 1 0 T0AND 0010X1XX 3 0 T0BITA 0XX010XX 2 0 NAME6:T0_ASLA_ROLA_LSRA 101010XX 2 0 T0TAX 101010XX 3 0 T0TAY 01X010XX 2 0 T0LSRA 01XXXXXX 2 X LSRLSRA 001000XX 3 5 T5JSRA XXX100XX 3 2 T2BR 000000XX 3 2 T2INT 001000XX 3 3 T3JSR XXXX01XX X 2 T2ANYZP XXXX00XX 1 2 T2ANYIND XXXXXXXX X 4 T4 XXXXXXXX X 3 T3 0X0000XX 3 0 T0RTIINT 01X011XX 3 0 T0JMP 0XX0X0XX 3 2 NAME3:T2_RTI_RTS_JSR_INT_PULA_PUPLP_PSHA_PSHP 011000XX 3 5 T5RTS XXXX1XXX X 2 T2ANYABS 100XXXXX 1 X STA 010010XX 3 2 T2PSHA XXX100XX 3 0 T0BR 0XX010XX 3 X PSHPULA XXX000XX 1 5 T5XIND XXXX1XXX X 3 T3ANYABS XXX100XX 1 4 T4INDYB XXX11XXX X 3 T3ABSXYB 0X0000XX 3 X RTIINT 001000XX 3 X JSR 01X011XX 3 X JMPB 11X00XXX 3 1 T1CPX2CY2 00X010XX 2 1 T1ASLARLA 11X011XX 3 1 T1CPX1CY1 110XXXXX 1 1 T1CMP X11XXXXX 1 1 T1ADCSBCB 00XXXXXX 2 X NAME5:ROL_ROLA_ASL_ASLA X1XXXXXX 2 X LSRRADCIC 0010X1XX 3 1 T1BIT 000010XX 3 2 T2PSHP 000000XX 3 4 T4INT 100XXXXX X X STASTYSTX XXX11XXX X 4 T4ABSXYB XXXX00XX 1 5 T5ANYIND XXX001XX X 2 T2ZP XXX011XX X 3 T3ABS XXX101XX X 3 T3ZPX 0X0010XX 3 2 T2PSHASHP 01X000XX 3 5 T5RTIRTS 001000XX 3 5 T5JSRB 01X011XX 3 5 T4JMP 010011XX 3 2 T2JMPABS 0X1010XX 3 3 T3PLAPLPB XXX100XX 3 3 T3BR 0010X1XX 3 0 T0BITB 010000XX 3 4 T4RTIB 001010XX 3 0 T0PULP 0XX010XX 3 X PSHPULB 101110XX 3 X CLV 00X110XX 3 0 T0CLCSEC 01X110XX 3 0 T0CLISEI 11X110XX 3 0 T0CLDSED 0XXXXXXX X X NI7P X0XXXXXX X X NI6P
The format is:
76543210 G T NAME
- The first column represents the 8 bits of the IR. 1 means the bit has to be 1 for the line to fire, 0 means the bit has to be 0, X is a don't care. Note that the lower two bits are always XX - the decode ROM doesn't actually check these, but check a cooked version of these bits instead.
- The second column is the "G" input, it must match 1, 2, 3 or it's a don't care. G is derived from the lower two bits of the IR:
G1 = IR0 G2 = IR1 G3 = !IR0 & !IR1
- The third column is "T", which is the clock cycle in which the line fires (0..5).
Some observations:
1. There are 15 duplicates in the decode ROM:
$ for i in `sort pla.txt | cut -c -12 | uniq -c | sort -n | grep "^ 2" | cut -c 6-17 | sed -e "s/ /./g"`; do grep $i pla.txt; done
We assume this has been done because they had no way of routing the output of some line where they wanted, so they put the same line at a different location again.
2. As an example, ADC # is 2 cycles, but there are lines that match T=[2..4]. In practice, these will never fire; they are meant for other instructions that have a similar encoding and do have T>2.
3. About G, and how it explains many illegal opcodes: Orlando and I reverse engineered this by dumping operation lists with decode.rb and filtering which Gs made sense. The funny thing here is that this leads to the table:
00 -> G3 01 -> G1 10 -> G2 11 -> G1/2
11 is the don't care case, there are no opcodes XXXXXX11 that are documented. So in order to simplify the G encoding, 11 has both G1 and G2 turned on, so all G=1 and G=2 lines fire. And this explains A LOT of things, like how LDA (0xAD, G=1) and LDX (0xAE, G=2) become LAX (0xAF, G=1 and G=2):
LDA T=0 XXXXXXXX X 0 T0A 101XXXXX 1 0 T0LDA XXXXXXXX 1 0 T0G1 X0XXXXXX X X NI6P LDX T=0 10XXXXXX 2 X LDXSDX 101XXXXX 2 0 T0TALDTSX XXXXXXXX X 0 T0A X0XXXXXX X X NI6P LAX T0 10XXXXXX 2 X LDXSDX 101XXXXX 2 0 T0TALDTSX XXXXXXXX X 0 T0A 101XXXXX 1 0 T0LDA XXXXXXXX 1 0 T0G1 X0XXXXXX X X NI6P
...which is pretty much LDA and LDX joined!
If you look at http://www.oxyron.de/html/opcodes02.html , you can see that columns 3, 7, B and F are illegal; this is the G=1+G=3 case. These columns basically execute all operations of the two preceding columns at the same time. Note that (as far as I checked) the cycle count (number in the table) is always the MAX() of the two opcodes it consists of.
This was known:
http://www.viceteam.org/plain/64doc.txt
Other undocumented instructions usually cause two preceding opcodes being executed.
But now we have more of a clue what's happening there...
Column 2 is KIL, column 3 has mostly *8* cycle instructions, which is weird. There are no regular 8 cycles ones. Not sure this is accurate in the docs. I see a correlation between the KIL and the 8 cycles. My theory is that KIL overflows the cycle counter. Not sure why column 3 doesn't inherit that feature.
The MAX() property and the KIL/Column 3 thing might explain how the cycle counter gets reset to 0... what triggers that. Orlando is also looking into this, comparing neighbor opcodes that terminate differently.
Here is the ruby program that accepts an opcode at the command line and prints the sequence of clocks:
#! /usr/bin/env ruby if ($*.length < 1) print "usage: #{$0} <value>\n" exit end opc = eval($*[0]) b0 = (opc & 1) != 0 b1 = (opc & 2) != 0 gmatch = Array.new gmatch[1] = b0 gmatch[2] = b1 gmatch[3] = !b0 && !b1 bin = ("%08b" % opc) input = Array.new File.open('pla.txt').each_line do |s| next if s =~ /^#.*/ # skip lines starting with '#' input += [ s.chop.split(/ /) ] end 6.times do |time| print "T=#{time}\n" input.each do |ni, g, t, name| print "#{ni} #{g} #{t} #{name}\n" if (bin.match(ni.gsub(/X/, ".")) && (t == "X" || time == t.to_i) && (g == "X" || gmatch[g.to_i])) end print "\n" end
It also needs to read a file 'pla.txt' which has a tabulation as found here.
Notes
- Template:EndnoteThe "Decode ROM" is named as a ROM in Hanson's block diagram, although it has wordline inputs and no address decoder. It is sometimes described as a PLA although it also lacks an AND plane. It is a structured layout of NOR gates with many common inputs, as compared to the unstructured gates found in the central decode logic, sometimes known as the random logic (meaning not structured).