8-bit computer op een breadboard

mel

Golden Member

Niet geheel off topic:
Ik werk het liefst met 6502 processors, en de bijbehorende hardware.
Ik kan de instructieset en de instructies bijna dromen. en ik heb er ook een hele zwik van liggen... :)
(en een Eprom programmer, dat is ook wel makkelijk )

u=ir betekent niet :U bent ingenieur..
tmdr

Golden Member

Haha maar dat is natuurlijk ook gigantisch mooi.
Ik denk dat we dat soort magische hardware, die het begin van dit computertijdperk wel zo'n beetje symboliseren, altijd moeten blijven koesteren.

Ik ben nog niet geheel zeker hiervan, maar afhankelijk van hoe het uitpakt, ga ik mijn eigen instructieset baseren op die van de 6502.

De 6502 staat ook nog op mijn lijstje met to-do projecten. Het lijkt me gaaf om een prototype Apple I te maken. Hier lokaal hebben ze 'm nergens en uit het verre Oosten durf ik dat soort dingen niet te bestellen ivm fake. Waar kan ik die het beste halen? En wat is een redelijke prijs (afhankelijk van de staat natuurlijk).

Welke programmer gebruik je trouwens?

Op 21 september 2017 11:02:49 schreef tmdr:
Hey Gerard,

Wat gaaf om te horen.
Heb je website even doorgespit. Je bent al flink op weg zie ik.

Wat betreft de instructie-set. Hoe heb je dat gedaan?

Ik heb een spreadsheet gemaakt waarin ik de eerste instructies heb uitgewerkt. Deze is verre van compleet en omdat ik ben geswitched naar de 74LS181 is hij ook verouderd en aan uitbreiding toe. Wanneer ik de Control Unit ga overzetten (binnenkort) zal ik de spreadsheet verder uitwerken en publiceren.

Ik neem aan dat je 2-byte instructies hebt?
Heb je ook single-byte instructies; wanneer een instructie geen address nodig heeft?

Op dit moment voorzie ik één en twee bytes instructies.

Zelf wil ik, op termijn, de boel ombouwen om 64k geheugen (64kb RAM, of 32kb ROM + 32kb RAM) te kunnen gebruiken. Hiervoor moet ik wel een aparte address bus gaan aanleggen, aangezien 64kb natuurlijk 16-bit addresses heeft.
Hierdoor kom ik uit op single-, 2- en 3-byte instructies. Met 3-byte instructies is absolute addressing mogelijk en met 2-byte instructies alleen relative addressing.
Dit zijn echter toekomstplannen, dus heb ik nog niet alles helemaal helder.

Ik heb dezelfde gedachte; het systeem op termijn naar 64K uitbreiden. Van wat ik me van de Z80 assembler herinner is het zo, dat er registerparen werden gebruikt voor adressering, bijvoorbeeld ax en bx, samen vormden ze dan een adres in het 64K geheugen. (of was dat nou de 6502?). In elk geval kun je dat de databus 8bits houden. De 16 bits address bus kun je dan op de memory-print laten plaatsvinden als je de adresseringsregisters daar ook plaatst.

Hoe heb je de ALU aangepakt?
Zelfde als Ben Eaters design?
edit: lees nu pas één van je eerdere artikelen waar je dit beschrijft. Heb je misschien wat meer info over hoe je dit hebt aangepakt?
Ik wil op termijn over gaan naar de 74LS181. Just for the fun of it.

Ik ga je website in de gaten houden! Super gaaf.
Misschien kan ik op termijn ook wat foto's plaatsen in dit topic. Moet eerst nog wat werken aan de control logic.

Leuk, laten we contact houden!

Ain't no place like 127.0.0.1

Op 21 september 2017 11:59:48 schreef mel:
Niet geheel off topic:
Ik werk het liefst met 6502 processors, en de bijbehorende hardware.
Ik kan de instructieset en de instructies bijna dromen. en ik heb er ook een hele zwik van liggen... :)
(en een Eprom programmer, dat is ook wel makkelijk )

Lijkt me ook wel leuk, maar in het kader van dit topic voel ik me verplicht (ahum) om te zeggen: werken met microprocessors is voor watjes... :) :) :)

Ain't no place like 127.0.0.1

Op 21 september 2017 12:05:11 schreef tmdr:
Haha maar dat is natuurlijk ook gigantisch mooi.
Ik denk dat we dat soort magische hardware, die het begin van dit computertijdperk wel zo'n beetje symboliseren, altijd moeten blijven koesteren.

Ik ben nog niet geheel zeker hiervan, maar afhankelijk van hoe het uitpakt, ga ik mijn eigen instructieset baseren op die van de 6502.

De 6502 staat ook nog op mijn lijstje met to-do projecten. Het lijkt me gaaf om een prototype Apple I te maken. Hier lokaal hebben ze 'm nergens en uit het verre Oosten durf ik dat soort dingen niet te bestellen ivm fake. Waar kan ik die het beste halen? En wat is een redelijke prijs (afhankelijk van de staat natuurlijk).

Welke programmer gebruik je trouwens?

Een paar linkjes:

Mouser offers the 65C02 for $6.99 today...

Artikel on Hackaday...

Gerard

Ain't no place like 127.0.0.1
Hewlett

Honourable Member

6502 CPU worden nog steeds door WDC gemaakt. Je kunt ook proberen een CM630P te vinden, dat is een koude oorlog Bulgaarse 6502 clone die volledig identiek aan de 6502 is en af toe in Oost Europa via eBay aangeboden wordt. De 6502 is door Michael Steil volledig transistor level reverse engineered (zie CCC presentatie: https://www.youtube.com/watch?v=fWqBmmPQP40) er is ook een transistor level simulatie van: http://www.visual6502.org/

HamRadio PA2HK // Keep Calm and Carry On.

Verder ploeteren... Ik heb een begin gemaakt met mijn instructieset. Tot nu toe is voorzien in 1, 2 en 3 bytes instructies.

Zie deze link voor een eerste ontwerp.

Edit: Link naar de beschikbare Control Signals.

Gerard

[Bericht gewijzigd door GerardWassink op zaterdag 23 september 2017 12:54:54 (21%)

Ain't no place like 127.0.0.1
tmdr

Golden Member

Ziet er goed uit Gerard!
Ik zie dat je alleen voor je MOV instructies 3 bytes gebruikt.
Is dat dan nog rendabel?
Ik wil graag 1-, 2- en 3-bytes instructies implementeren omdat ik voor 16-bit adressen ga.
Voor 8-bit adressen lijkt me 3-bytes overkill.
Of heb je dit met een specifieke reden gedaan? Gebaseerd op een bestaande instructieset?

De INC instructies lijken mij niet optimaal ivm de destructiveness voor A en B.
Aangezien ik voor een separate 16-bit address bus ga, wil ik de INC (instructie of step in microcode, bijv voor het fetchen van multi-byte instructions) natuurlijk via de (tegen die tijd) 16-bit PC doen.
Mijn instructieset zal ongeveer als volgt gaan worden: 1-byte voor NOP, ADD, etc, 2-byte voor immediate OPs en relative addressing (dus max +-8-bits) en 3-bytes voor absolute addressing. Voor relative addressing ga ik waarschijnlijk 74LS283 gebruiken.

Mijn huidige 3 byte instructie (is er maar eentje) is een memory to memory move. Later is er waarschijnlijk geen enkel bezwaar (indien nodig) om deze te laten vervallen, maar dit is uit nostalgische overwegingen i.v.m. mijn IBM 370 mainframe Assembler achtergrond.

Daar was het nog wel wat uitgebreider, de instructie luidt:

MVC D1(L,B1),D2(B2)

Uitleg:

Gerard

Ain't no place like 127.0.0.1

Het decoderen van zo'n instructie is een heel gedoe. Ik zou me beperken tot load-store, dus max 1 argument.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Eindelijk!

Ik heb de fout in mijn output module gevonden. Twee pootjes aan elkaar gesoldeerd, bijna niet zichtbaar, maar toch... Ze zorgden voor 'ghost images' - althans zo leek het. De twee most significant 7 segment displays kregen allebei de voeding van zichzelf, EN van de ander.

Maar het werkt, zie ook de post op mijn website met een video'tje.

Ain't no place like 127.0.0.1
mel

Golden Member

Op 21 september 2017 12:05:11 schreef tmdr:

Welke programmer gebruik je trouwens?

Een heel simpele programmer, werkt onder Windows, en is van het Duitse bedrijf Batronic :)
Werkt via de par. poort van een PC.

u=ir betekent niet :U bent ingenieur..
tmdr

Golden Member

Op 24 september 2017 12:36:39 schreef GerardWassink:
Eindelijk!

Ik heb de fout in mijn output module gevonden. Twee pootjes aan elkaar gesoldeerd, bijna niet zichtbaar, maar toch... Ze zorgden voor 'ghost images' - althans zo leek het. De twee most significant 7 segment displays kregen allebei de voeding van zichzelf, EN van de ander.

Maar het werkt, zie ook de post op mijn website met een video'tje.

Dat zijn inderdaad rottige dingen!
Leuk dat je ons zo update!
Ik ga vandaag misschien de eerste stappen zetten met het leggen van alle control lines.
Gisteren de bus helemaal netjes aangesloten. Had dit nog met jumper wires zitten, omdat ik nog niet zeker was of ik in de toekomst de 16-bit address bus ook op een dergelijke manier ga doen. Inmiddels besloten dat is ik dit op een andere manier ga doen.

Misschien dat ik vanmiddag de boel iets netter kan maken en wat foto's kan plaatsen.

Op 24 september 2017 13:26:35 schreef mel:
[...]
Een heel simpele programmer, werkt onder Windows, en is van het Duitse bedrijf Batronic :)
Werkt via de par. poort van een PC.

Phoe die is redelijk duur!
Helaas zit dat er voor mij nog niet in ;-)

Op 24 september 2017 13:48:22 schreef tmdr:

Leuk dat je ons zo update!

Graag gedaan...
Misschien een eigen draadje openen? Of vind je't niet erg?

Gerard

Ain't no place like 127.0.0.1
tmdr

Golden Member

Nee zeker niet!
Juist leuk als we hier samenvattend elkaars progressie zien.
Wie weet inspireert het anderen om het zelfde te doen.

Mijn idee...
Ik loop wel tegen een uitdaging aan, even in het engels:

[engels]
Microcode for 8bit computer instructions

My 8 bit instructions can have up to 8 microcode steps each; I defined up to 24 control signals (thus needing 3 bytes per step); So in Arduino I have to define them as uint32_t variables (which are 4 bytes long).

The EEPROMs have 8 bit values, so to hold one control words, I need 3 EEPROMs in parallel; I named those 3 EEPROMs CU02, CU01 and CU00, from msb to lsb. Control word CW is spread over the EEPROMs as follows:

  • CU02 receives (CW >> 16) & 0xFF
  • CU01 receives (CW >> 8) & 0xFF
  • CU00 receives CW & 0xFF

so:

  • CU02 contains bits 23 to 16
  • CU01 contains bits 15 to 08
  • CU00 contains bits 07 to 00

That's the plan.

But...

The complete microcode consists of 256 instructions x 8 steps x 4 bytes per step. this amounts to 8192 bytes of storage for the microcode. Alas, this will not fit in Arduino Nano's memory... If I choose to go along this path, I have to chop it up in 8 (eight) parts to be able to program the EEPROMs. The nasty disadvantage is that when the code has to change, I would have to do that 8 times... Being an old-school programmer, I hate that.

What else?

Should I choose to program one EEPROM at a time, I would need only byte-sized variables, 256 * 8 of them, which would need 2K bytes of memory. Even this wouldn't fit, The Nano can only process half of that...

I'm thinking about some other way...

[/engels]

Ain't no place like 127.0.0.1
tmdr

Golden Member

Het is natuurlijk helemaal niet nodig dat alles in het flash geheugen van de Nano zit.
Misschien is het makkelijker om de Nano puur als interface te gebruiken.
Die krijgt via de Serial een commando op op address x value y te schrijven.
En dan met Python (or whatever suits you) wat je normaal op je Nano doet vanaf je PC over de serial sturen.

Ik zelf wil eigenlijk ook meer naar zo'n implementatie, puur omdat ik het heel rottig vind om steeds nieuwe binaries voor de Arduino te moeten compileren en te uploaden.
Als je niet zo veel op hebt met de software, misschien dat we dan iets samen kunnen doen?
Software is mijn vak, dus voor mij is het een fluitje van een cent. Wie weet hebben anderen er ook nog wat aan..!

Lijkt me leuk.

Een snelle zoektocht op het web leverde nog niet direct iets op. Ik heb ook even overwogen om iets via de Raspberry Pi te doen, die heeft in elk geval veel meer geheugen en een volwassen OS.

Daartoe ben ik al even in Python bezig geweest:

c code:


#!/usr/bin/python

#
# Define the values for the control signals
#

# EEPROM 2, bits D23 - D16

CE		= 0b100000000000000000000000  # 0x800000 - Count Enable
HLT		= 0b010000000000000000000000  # 0x400000 - Halt
PCI		= 0b001000000000000000000000  # 0x200000 - PC In
PCO		= 0b000100000000000000000000  # 0x100000 - PC Out
MAI		= 0b000010000000000000000000  # 0x080000 - Memory Address In
MI		= 0b000001000000000000000000  # 0x040000 - Memory In
MO		= 0b000000100000000000000000  # 0x020000 - Memory Out
IRI		= 0b000000010000000000000000  # 0x010000 - Instruction Register In

# EEPROM 1, bits D15 - D08

EO		= 0b000000001000000000000000  # 0x008000 - Sigma Out (ALU value)
OI		= 0b000000000100000000000000  # 0x004000 - Output In
AI		= 0b000000000010000000000000  # 0x002000 - A Register In
AO		= 0b000000000001000000000000  # 0x001000 - A register Out
BI		= 0b000000000000100000000000  # 0x000800 - B register In
BO		= 0b000000000000010000000000  # 0x000400 - B register Out
ALM		= 0b000000000000001000000000  # 0x000200 - ALU Mode
AL0		= 0b000000000000000100000000  # 0x000100 - ALU function 0

# EEPROM 0, bits D07 - D00

AL1		= 0b000000000000000010000000  # 0x000080 - ALU function 1
AL2		= 0b000000000000000001000000  # 0x000040 - ALU function 2
AL3		= 0b000000000000000000100000  # 0x000020 - ALU function 3
ALCI	= 0b000000000000000000010000  # 0x000010 - ALU Carry In
n3		= 0b000000000000000000001000  # 0x000008 - 
n2		= 0b000000000000000000000100  # 0x000004 - 
n1		= 0b000000000000000000000010  # 0x000002 - 
n0		= 0b000000000000000000000001  # 0x000001 - 

#
# Define the control words per machine code instruction
# 256 instructions x 8 bytes = 2K bytes
#

instr = [

# === NO Operation
#
  0x00, MAI|PCO, MO|IRI|CE, 0,						0,					0,						0,							0,	0,	# NOP

# === LOAD instructions
#
  0x01, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|CE|AI,			0,						0,							0,	0,	# LDAi, val
  0x02, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|AI|CE,				0,							0,	0,	# LDAm addr

  0x07, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|CE|BI,			0,        				0,							0,	0,	# LDBi, val
  0x08, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|BI|CE, 				0,							0,	0,	# LDBm addr


# === STORE instructions
#
  0x10, MAI|PCO, MO|IRI|CE, PCO|MAI, 				MO|MAI,				AO|MI|CE, 				0,							0,	0,   # STAm addr
  0x11, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				BO|MI|CE,				0,							0,	0,   # STBm addr

  
# === ARITHMETIC instructions
#
  0x20, MAI|PCO, MO|IRI|CE, AL3|AL0|EO|AI|CE,   	0,					0,						0,							0,	0,	# ADD
  0x21, MAI|PCO, MO|IRI|CE, PCO|MAI,  				MO|BI,				AL3|AL0|EO|AI|CE,		0,							0,	0,	# ADDi val
  0x22, MAI|PCO, MO|IRI|CE, PCO|MAI,  				MO|MAI,				MO|BI,					AL3|AL0|EO|AI|CE,			0,	0,	# ADDm addr

  0x24, MAI|PCO, MO|IRI|CE, AL2|AL1|EO|AI|CE,   	0,					0,						0,							0,	0,	# SUB
  0x25, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|BI,				AL2|AL1|EO|AI|CE,		0,							0,	0,	# SUBi val
  0x26, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|BI,					AL2|AL1|EO|AI|CE,			0,	0,	# SUBm addr

  0x28, MAI|PCO, MO|IRI|CE, AO|BI,					ALM|AL3|AL2|EO|AI,	AL3|AL0|EO|AI,			AO|BI,  					0,	0,	# INCA
  0x29, MAI|PCO, MO|IRI|CE, ALM|AL3|AL2|EO|AI,		AL3|AL0|EO|AI,		AO|BI,					0,							0,	0,	# INCB


# === LOGIC instructions
#
  0x30, MAI|PCO, MO|IRI|CE, ALM|AL2|AL1|EO|AI|CE,	0,					0,						0,							0,	0,	# XOR
  0x31, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|BI,				ALM|AL2|AL1|EO|AI|CE,	0,							0,	0,	# XORi val
  0x32, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|BI,					ALM|AL2|AL1|EO|AI|CE,		0,	0,	# 0x32 - XORm mem

  0x34, MAI|PCO, MO|IRI|CE, ALM|AL3|AL1|AL0|EO|AI|CE,	0,				0,						0,							0,	0,	# AND
  0x35, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|BI,				ALM|AL3|AL1|AL0|EO|AI|CE,	0,						0,	0,		# ANDi val
  0x36, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|BI,					ALM|AL3|AL1|AL0|EO|AI|CE,	0,	0,	# ANDm mem

  0x38, MAI|PCO, MO|IRI|CE, ALM|AL3|AL2|AL1|EO|AI|CE,	0,				0,						0,							0,	0,	# OR
  0x39, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|BI,				ALM|AL3|AL2|AL1|EO|AI|CE,	0,						0,	0,	# ORi val
  0x3A, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|BI,					ALM|AL3|AL2|AL1|EO|AI|CE,	0,	0,	# ORm mem

  0x3C, MAI|PCO, MO|IRI|CE, ALM|EO|AI,				0,					0,						0,							0,	0,	# NOTA
  0x3D, MAI|PCO, MO|IRI|CE, ALM|AL2|AL0|EO|BI,		0,					0,						0,							0,	0,	# NOTB
  0x3E, MAI|PCO, MO|IRI|CE, ALM|AL1|AL0|EO|AI,		0,					0,						0,							0,	0,	# CLRA
  0x3F, MAI|PCO, MO|IRI|CE, ALM|AL1|AL0|EO|BI,		0,					0,						0,							0,	0,	# CLRB

# === JUMP instructions
#
  0x40, MAI|PCO, MO|IRI|CE,	PCO|MAI,				MO|PCI,				0,						0,							0,	0,	# JMPi val
  0x41, MAI|PCO, MO|IRI|CE,	PCO|MAI,				MO|MAI,				MO|PCI,					0,							0,	0,	# JMPm addr

  
# === OUTPUT instructions
#
  0x50, MAI|PCO, MO|IRI|CE,	AO|OI,					0,					0,						0,							0,	0,	# OUTA
  0x51, MAI|PCO, MO|IRI|CE, BO|OI,					0,					0,						0,							0,	0,	# OUTB

  0x54, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|OI|CE,			0,						0,							0,	0,	# OUTi
  0x55, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|OI|CE,				0,							0,	0,	# OUTm


# === MOVE instructions
#
  0x60, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|BI|CE,			PCO|MAI,				BO|MI|CE,					0,	0,			# MOVi val
  0x61, MAI|PCO, MO|IRI|CE, PCO|MAI,				MO|MAI,				MO|BI|CE,				PCO|MAI,					BO|MI|CE,	0,	# MOVm ad1, ad2


# === HALT instruction
#
  0xFF, MAI|PCO, MO|IRI|CE,	HLT,					0,					0,						0,							0,	0	# HLT
]

print " "
print "OPCD -   step1  -   step2  -   step3  -   step4  -   step5  -   step6  -   step7  -   step8"
for n in range(0, len(instr)):
	if ( (n % 9) == 0 ):
		print " "
		print (hex(instr[n])+"00")[:4], "-",
	else:
		str = (hex(instr[n])[2:]+"000000")[:6]
		print str[:2], str[2:4], str[4:6], " ",

exit()

De output is nu:

code:


 
OPCD -   step1  -   step2  -   step3  -   step4  -   step5  -   step6  -   step7  -   step8
 
0x00 - 18 00 00   83 00 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x10 - 18 00 00   83 00 00   18 00 00   82 20 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x20 - 18 00 00   83 00 00   18 00 00   a0 00 00   82 20 00   00 00 00   00 00 00   00 00 00    
0x70 - 18 00 00   83 00 00   18 00 00   82 08 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x80 - 18 00 00   83 00 00   18 00 00   a0 00 00   82 08 00   00 00 00   00 00 00   00 00 00    
0x10 - 18 00 00   83 00 00   18 00 00   a0 00 00   84 10 00   00 00 00   00 00 00   00 00 00    
0x11 - 18 00 00   83 00 00   18 00 00   a0 00 00   84 04 00   00 00 00   00 00 00   00 00 00    
0x20 - 18 00 00   83 00 00   80 a1 20   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x21 - 18 00 00   83 00 00   18 00 00   20 80 00   80 a1 20   00 00 00   00 00 00   00 00 00    
0x22 - 18 00 00   83 00 00   18 00 00   a0 00 00   20 80 00   80 a1 20   00 00 00   00 00 00    
0x24 - 18 00 00   83 00 00   80 a0 c0   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x25 - 18 00 00   83 00 00   18 00 00   20 80 00   80 a0 c0   00 00 00   00 00 00   00 00 00    
0x26 - 18 00 00   83 00 00   18 00 00   a0 00 00   20 80 00   80 a0 c0   00 00 00   00 00 00    
0x28 - 18 00 00   83 00 00   18 00 00   a2 60 00   a1 20 00   18 00 00   00 00 00   00 00 00    
0x29 - 18 00 00   83 00 00   a2 60 00   a1 20 00   18 00 00   00 00 00   00 00 00   00 00 00    
0x30 - 18 00 00   83 00 00   80 a2 c0   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x31 - 18 00 00   83 00 00   18 00 00   20 80 00   80 a2 c0   00 00 00   00 00 00   00 00 00    
0x32 - 18 00 00   83 00 00   18 00 00   a0 00 00   20 80 00   80 a2 c0   00 00 00   00 00 00    
0x34 - 18 00 00   83 00 00   80 a3 a0   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x35 - 18 00 00   83 00 00   18 00 00   20 80 00   80 a3 a0   00 00 00   00 00 00   00 00 00    
0x36 - 18 00 00   83 00 00   18 00 00   a0 00 00   20 80 00   80 a3 a0   00 00 00   00 00 00    
0x38 - 18 00 00   83 00 00   80 a2 e0   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x39 - 18 00 00   83 00 00   18 00 00   20 80 00   80 a2 e0   00 00 00   00 00 00   00 00 00    
0x3a - 18 00 00   83 00 00   18 00 00   a0 00 00   20 80 00   80 a2 e0   00 00 00   00 00 00    
0x3c - 18 00 00   83 00 00   a2 00 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x3d - 18 00 00   83 00 00   8b 40 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x3e - 18 00 00   83 00 00   a3 80 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x3f - 18 00 00   83 00 00   8b 80 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x40 - 18 00 00   83 00 00   18 00 00   22 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x41 - 18 00 00   83 00 00   18 00 00   a0 00 00   22 00 00   00 00 00   00 00 00   00 00 00    
0x50 - 18 00 00   83 00 00   50 00 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x51 - 18 00 00   83 00 00   44 00 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x54 - 18 00 00   83 00 00   18 00 00   82 40 00   00 00 00   00 00 00   00 00 00   00 00 00    
0x55 - 18 00 00   83 00 00   18 00 00   a0 00 00   82 40 00   00 00 00   00 00 00   00 00 00    
0x60 - 18 00 00   83 00 00   18 00 00   82 08 00   18 00 00   84 04 00   00 00 00   00 00 00    
0x61 - 18 00 00   83 00 00   18 00 00   a0 00 00   82 08 00   18 00 00   84 04 00   00 00 00    
0xff - 18 00 00   83 00 00   40 00 00   00 00 00   00 00 00   00 00 00   00 00 00   00 00 00  
Ain't no place like 127.0.0.1
tmdr

Golden Member

Vanavond ga ik even zitten voor een simpele Python interfacing library en een receiver library voor de Arduino’s.
Houd je er wel rekening mee dat de RPi’s 3.3v zijn qua GPIO?
Volgens mij heeft de GPIO header wel een 5v pin, maar de ROM pinnen aansturen vanaf een Pi is dus niet echt een feest. Ik zou het lekker bij een Arduino houden. Bovendien hoef je dan alleen met de software te knoeien.

tmdr

Golden Member

Gerard, helaas weinig tijd gehad vanavond ivm colleges die ver uit liepen.
Alleen de host interface kunnen tikken. Heb nog niets gerund dus vergeef me alle tikfouten en de kinderziektes. Fatsoenlijk testen is ook nog niet echt mogelijk zonder client natuurlijk.

Kleine toelichting van hoe ik het heb opgezet. Zo simpel mogelijk, efficiëntie is natuurlijk ver te zoeken.
Is dan ook niet echt nodig. Voor het lezen of schrijven lijkt het me verstandig om eerst een RESET signal te sturen, mocht er iets onbedoeld gebeuren voor deze operatie, kan hiermee de MCU in een state worden gebracht waarvan we zeker weten dat we kunnen gaan versturen. Eventueel wachten op een "ready" bevestiging verstandig. Verder zijn de RESET, WRITE en READ OPs simpele control signals. Nu natuurlijk maar twee bits, maar worden als 8-bits waarde verstuurd. Nogmaals, om de boel simpel te houden. En we hebben natuurlijk niet heel veel meer info te versturen.
Verder lijkt me de code voor zich spreken.

Ik heb jouw gedefinieerde instructies gepakt als basis. Zo ver ben ik zelf nog niet.
Heb naast de interfacing ook een kleine opzet gemaakt voor het schrijven van die instructies adhv de interface.
Daarvoor heb ik overigens aangenomen dat de verschillende instructies die in je code stonden puur de 8-bit instructiecodes zelf zijn en niet de daadwerkelijke adressen (maar << 3, zie code).

Morgen ben ik weer de hele dag bezig, misschien in de avond nog wat tijd!

interface.py

c code:

import serial

RESET_OP = 0x0
WRITE_OP = 0x1
READ_OP = 0x2

class ProgrammerInterface:
    def __init__(self, serial_port, baud_rate=57600):
        self._serial = serial.Serial(serial_port, baud_rate)
        # time.sleep(2)

    """
    Writes occur by letting the receiving party know that we want to write by
    sending the WRITE_OP (8-bit).
    Dependent on whether `address` is a list or a plain address, batch mode or
    normal mode is detected. When in batch mode, and `data` is a list, both lists
    are enumerated. When in batch mode and `data` is a single, plain value, only
    the address list is enumerated and sends the value for each address in the list.
    """
    def write(self, address, data):
        def send(address, data):
            self._serial.write(chr(WRITE_OP))
            self._serial.write(chr((address >> 8) & 0xFF))
            self._serial.write(chr(address & 0xFF))
            self._serial.write(chr(data & 0xFF))

        self._serial.write(chr(RESET_OP))

        if type(address) is list:
            if type(data) is list:
                if len(data) < len(address):
                    raise Exception("Not enough data entries")
                for i in range(0, len(address)):
                    send(address[i], data[i])
            else:
                for i in range(0, len(address)):
                    send(address[i], data)
        else:
            send(address, data)

    """
    Reads occur by letting the receiving party know that we want to read by
    sending the READ_OP (8-bit).
    Dependent on weather `address` is a list or a plain address, batch mode or
    normal mode is detected. When in batch mode the values of all given addresses
    are queried and appended into the output stack. Read values are expected to
    terminate with a linefeed (hence, readline) for simplicity sake.
    """
    def read(self, address):
        def send(address):
            self._serial.write(chr(READ_OP))
            self._serial.write(chr((address >> 8) & 0xFF))
            self._serial.write(chr(address & 0xFF))

            return self._serial.readline()[:2]

        self._serial.write(chr(RESET_OP))

        if type(address) is list:
            output = []
            for i in address:
                output.append(send(i))
            return output
        else:
            return send(i)

programmer.py:

c code:

#!/usr/bin/python

import sys
from interface import ProgrammerInterface

if len(sys.argv) > 2:
    rom, serial_port, baud_rate = int(sys.argv[1]), sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 57600
else:
    raise Exception("Invalid arguments")
 
#
# Define the values for the control signals
#
 
# EEPROM 2, bits D23 - D16
 
CE      = 1 << 23  # 0x800000 - Count Enable
HLT     = 1 << 22  # 0x400000 - Halt
PCI     = 1 << 21  # 0x200000 - PC In
PCO     = 1 << 20  # 0x100000 - PC Out
MAI     = 1 << 19  # 0x080000 - Memory Address In
MI      = 1 << 18  # 0x040000 - Memory In
MO      = 1 << 17  # 0x020000 - Memory Out
IRI     = 1 << 16  # 0x010000 - Instruction Register In
 
# EEPROM 1, bits D15 - D08
 
EO      = 1 << 15  # 0x008000 - Sigma Out (ALU value)
OI      = 1 << 14  # 0x004000 - Output In
AI      = 1 << 13  # 0x002000 - A Register In
AO      = 1 << 12  # 0x001000 - A register Out
BI      = 1 << 11  # 0x000800 - B register In
BO      = 1 << 10  # 0x000400 - B register Out
ALM     = 1 <<  9  # 0x000200 - ALU Mode
AL0     = 1 <<  8  # 0x000100 - ALU function 0
 
# EEPROM 0, bits D07 - D00
 
AL1     = 1 <<  7  # 0x000080 - ALU function 1
AL2     = 1 <<  6  # 0x000040 - ALU function 2
AL3     = 1 <<  5  # 0x000020 - ALU function 3
ALCI    = 1 <<  4  # 0x000010 - ALU Carry In
n3      = 1 <<  3  # 0x000008 - 
n2      = 1 <<  2  # 0x000004 - 
n1      = 1 <<  1  # 0x000002 - 
n0      = 1 <<  0  # 0x000001 - 

"""
    Constant control words
"""
CW_0    = MAI | PCO
CW_1    = MO | IRI | CE
 
#
# Define the control words per machine code instruction
# 256 instructions x 8 bytes = 2K bytes
#
 
instr = {
 
# === NO Operation
#
  0x00: [ CW_0, CW_1, 0,                      0,                  0,                      0,                          0,  0, ], # NOP
 
# === LOAD instructions
#
  0x01: [ CW_0, CW_1, PCO|MAI,                MO|CE|AI,           0,                      0,                          0,  0, ], # LDAi, val
  0x02: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|AI|CE,               0,                          0,  0, ], # LDAm addr
 
  0x07: [ CW_0, CW_1, PCO|MAI,                MO|CE|BI,           0,                      0,                          0,  0, ], # LDBi, val
  0x08: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|BI|CE,               0,                          0,  0, ], # LDBm addr
 
 
# === STORE instructions
#
  0x10: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             AO|MI|CE,               0,                          0,  0, ], # STAm addr
  0x11: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             BO|MI|CE,               0,                          0,  0, ], # STBm addr
 
 
# === ARITHMETIC instructions
#
  0x20: [ CW_0, CW_1, AL3|AL0|EO|AI|CE,       0,                  0,                      0,                          0,  0, ], # ADD
  0x21: [ CW_0, CW_1, PCO|MAI,                MO|BI,              AL3|AL0|EO|AI|CE,       0,                          0,  0, ], # ADDi val
  0x22: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|BI,                  AL3|AL0|EO|AI|CE,           0,  0, ], # ADDm addr
 
  0x24: [ CW_0, CW_1, AL2|AL1|EO|AI|CE,       0,                  0,                      0,                          0,  0, ], # SUB
  0x25: [ CW_0, CW_1, PCO|MAI,                MO|BI,              AL2|AL1|EO|AI|CE,       0,                          0,  0, ], # SUBi val
  0x26: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|BI,                  AL2|AL1|EO|AI|CE,           0,  0, ], # SUBm addr
 
  0x28: [ CW_0, CW_1, AO|BI,                  ALM|AL3|AL2|EO|AI,  AL3|AL0|EO|AI,          AO|BI,                      0,  0, ], # INCA
  0x29: [ CW_0, CW_1, ALM|AL3|AL2|EO|AI,      AL3|AL0|EO|AI,      AO|BI,                  0,                          0,  0, ], # INCB
 
 
# === LOGIC instructions
#
  0x30: [ CW_0, CW_1, ALM|AL2|AL1|EO|AI|CE,   0,                  0,                      0,                          0,  0, ], # XOR
  0x31: [ CW_0, CW_1, PCO|MAI,                MO|BI,              ALM|AL2|AL1|EO|AI|CE,   0,                          0,  0, ], # XORi val
  0x32: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|BI,                  ALM|AL2|AL1|EO|AI|CE,       0,  0, ], # 0x32 - XORm mem
 
  0x34: [ CW_0, CW_1, ALM|AL3|AL1|AL0|EO|AI|CE,   0,              0,                      0,                          0,  0, ], # AND
  0x35: [ CW_0, CW_1, PCO|MAI,                MO|BI,              ALM|AL3|AL1|AL0|EO|AI|CE,   0,                      0,  0, ], # ANDi val
  0x36: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|BI,                  ALM|AL3|AL1|AL0|EO|AI|CE,   0,  0, ], # ANDm mem
 
  0x38: [ CW_0, CW_1, ALM|AL3|AL2|AL1|EO|AI|CE,   0,              0,                      0,                          0,  0, ], # OR
  0x39: [ CW_0, CW_1, PCO|MAI,                MO|BI,              ALM|AL3|AL2|AL1|EO|AI|CE,   0,                      0,  0, ], # ORi val
  0x3A: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|BI,                  ALM|AL3|AL2|AL1|EO|AI|CE,   0,  0, ], # ORm mem
 
  0x3C: [ CW_0, CW_1, ALM|EO|AI,              0,                  0,                      0,                          0,  0, ], # NOTA
  0x3D: [ CW_0, CW_1, ALM|AL2|AL0|EO|BI,      0,                  0,                      0,                          0,  0, ], # NOTB
  0x3E: [ CW_0, CW_1, ALM|AL1|AL0|EO|AI,      0,                  0,                      0,                          0,  0, ], # CLRA
  0x3F: [ CW_0, CW_1, ALM|AL1|AL0|EO|BI,      0,                  0,                      0,                          0,  0, ], # CLRB
 
# === JUMP instructions
#
  0x40: [ CW_0, CW_1, PCO|MAI,                MO|PCI,             0,                      0,                          0,  0, ], # JMPi val
  0x41: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|PCI,                 0,                          0,  0, ], # JMPm addr
 
 
# === OUTPUT instructions
#
  0x50: [ CW_0, CW_1, AO|OI,                  0,                  0,                      0,                          0,  0, ], # OUTA
  0x51: [ CW_0, CW_1, BO|OI,                  0,                  0,                      0,                          0,  0, ], # OUTB
 
  0x54: [ CW_0, CW_1, PCO|MAI,                MO|OI|CE,           0,                      0,                          0,  0, ], # OUTi
  0x55: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|OI|CE,               0,                          0,  0, ], # OUTm
 
 
# === MOVE instructions
#
  0x60: [ CW_0, CW_1, PCO|MAI,                MO|BI|CE,           PCO|MAI,                BO|MI|CE,                   0,  0, ], # MOVi val
  0x61: [ CW_0, CW_1, PCO|MAI,                MO|MAI,             MO|BI|CE,               PCO|MAI,            BO|MI|CE,   0, ], # MOVm ad1, ad2
 
 
# === HALT instruction
#
  0xFF: [ MAI|PCO, MO|IRI|CE, HLT,            0,                  0,                      0,                          0,  0, ], # HLT
}

interface = ProgrammerInterface(serial_port, baud_rate)

for op, contr in instr.iteritems():
    address = op << 3
    for i in range(0, len(contr)):
        interface.write(address + i, contr[i] >> rom)

Hi,

Op welk systeem programmer jij? Op mijn MacBook krijg ik:

code:


enterprise:~ gerard$ ./test_programmer.py 
Traceback (most recent call last):
  File "./test_programmer.py", line 4, in <module>
    from interface import ProgrammerInterface
ImportError: No module named interface
enterprise:~ gerard$ 
Ain't no place like 127.0.0.1

Zoals de foutmelding zegt: Er is een python module (library) genaamd "interface" en die kan ie niet vinden. Of dat iets is wat je van het internet kan halen of dat het iets is wat tmdr gemaakt heeft weet ik niet.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 27 september 2017 16:15:05 schreef rew:
Zoals de foutmelding zegt: Er is een python module (library) genaamd "interface" en die kan ie niet vinden. Of dat iets is wat je van het internet kan halen of dat het iets is wat tmdr gemaakt heeft weet ik niet.

Als je goed kijkt is dat niet mijn vraag. Mijn vraag was op welk systeem hij ontwikkelt, wellicht / waarschijnlijk is die module systeem-afhankelijk.

Gerard

Ain't no place like 127.0.0.1
tmdr

Golden Member

Sorry ik had wel wat meer info mogen geven.
Ik werk ook op een Mac, Python 2.7.

Je moet de twee losse bestanden in een map zetten, met de namen zoals de boven de bestanden in het betreffende bericht staan. Dan krijg je een structuur als dit:

code:


eeprom-programmer/
  interface.py
  programmer.py

Interface.py is dus de module die nu nog mist.

Uitvoeren kan met de volgende argumenten:

code:


cd [path-to]/eeprom-programmer/
./programmer.py 0 /dev/cu.usbserial-A50285BI [baud-rate]

De command-line argumenten zijn dus:

code:


0 - EEPROM #
1 - USB device
2 - baud rate (optional)

Dit is de code voor op een Arduino, gebaseerd op die van Ben Eater grotendeels:

c code:


/**
 * This sketch programs the microcode EEPROMs for the 8-bit breadboard computer
 * See this video for more: https://youtu.be/JUVt_KYAp-I
 */
#define SHIFT_DATA 2
#define SHIFT_CLK 3
#define SHIFT_LATCH 4
#define EEPROM_D0 5
#define EEPROM_D7 12
// PIN 13 = PB5
#define WRITE_EN B10000

/*
 * Pulse WE for ~500ns.
 */
void pulse_write_enable() {
  PORTB &= ~WRITE_EN; // pin LOW
  __asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t"); // delay 500ns (8 * 62.5ns)
  PORTB |= WRITE_EN; // pin HIGH
  delay(10);
}


/*
 * Output the address bits and outputEnable signal using shift registers.
 */
void setAddress(int address, bool outputEnable) {
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80));
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address);

  digitalWrite(SHIFT_LATCH, LOW);
  digitalWrite(SHIFT_LATCH, HIGH);
  digitalWrite(SHIFT_LATCH, LOW);
}


/*
 * Set pinMode on all IO pins
 */
void io_mode(uint8_t mode) {
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin++)
    pinMode(pin, mode);
}


/*
 * Read a byte from the EEPROM at the specified address.
 */
byte readEEPROM(int address) {
  io_mode(INPUT);
  setAddress(address, /*outputEnable*/ true);

  byte data = 0;
  for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin -= 1) {
    data = (data << 1) + digitalRead(pin);
  }
  return data;
}


/*
 * Write a byte to the EEPROM at the specified address.
 */
void writeEEPROM(int address, byte data) {
  setAddress(address, /*outputEnable*/ false);
  io_mode(OUTPUT);

  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    digitalWrite(pin, data & 1);
    data = data >> 1;
  }
  pulse_write_enable();
}

enum ops {
  RESET_OP = 0x0,
  WRITE_OP = 0x1,
  READ_OP = 0x2,
};
enum state_t {
  READY_STATE,
  WRITE_ADDRESS_MSB_STATE,
  WRITE_ADDRESS_LSB_STATE,
  WRITE_DATA_STATE,
  READ_ADDRESS_MSB_STATE,
  READ_ADDRESS_LSB_STATE
};
state_t state = READY_STATE;
uint16_t buf = 0;

void receive_byte(byte b) {
  switch (state) {
    case READY_STATE:
      receive_op(b);
      break;
    case WRITE_ADDRESS_MSB_STATE:
    case READ_ADDRESS_MSB_STATE:
    case WRITE_ADDRESS_LSB_STATE:
    case READ_ADDRESS_LSB_STATE:
      receive_address(b);
      break;
    case WRITE_DATA_STATE:
      writeEEPROM(buf, b); // buf = the address, b = the data byte
      break;
  }
}

void receive_op(byte op) {
  buf = 0;
  switch (op) {
    case RESET_OP:
      state = READY_STATE;
      break;
    case WRITE_OP:
      state = WRITE_ADDRESS_MSB_STATE;
      break;
    case READ_OP:
      state = READ_ADDRESS_MSB_STATE;
  }
}

void receive_address(byte b) {
  buf = buf << 8;
  buf |= b;

  switch (state) {
    case WRITE_ADDRESS_MSB_STATE:
      state = WRITE_ADDRESS_LSB_STATE;
      break;
    case WRITE_ADDRESS_LSB_STATE:
      state = WRITE_DATA_STATE;
      break;
    case READ_ADDRESS_MSB_STATE:
      state = READ_ADDRESS_LSB_STATE;
      break;
    case READ_ADDRESS_LSB_STATE:
      send_data(buf); // buf = the address
      break;
  }
}

void send_data(uint16_t address) {
  Serial.println(readEEPROM(address));
}


void setup() {
  // put your setup code here, to run once:
  pinMode(SHIFT_DATA, OUTPUT);
  pinMode(SHIFT_CLK, OUTPUT);
  pinMode(SHIFT_LATCH, OUTPUT);
  digitalWrite(WRITE_EN, HIGH);
  pinMode(WRITE_EN, OUTPUT);
  Serial.begin(57600);
}


void loop() {
  while (Serial.available() > 0) {
    byte b = Serial.read();
    receive_byte(b);
  }
}

Stelt niet veel voor zoals je ziet. Past ook op de goedkope Nano's met een ATMega168 met slechts 16kb flash of zelfs kleiner.
Helaas nog niet kunnen testen tot op heden. Als er bugs oid in zitten zien we dat vanzelf.
De WE low voor <1us heb ik op een iets wat dirty manier gedaan. DelayMicroseconds(1), dat Ben gebruikt, icm de ballast van digitalWrite() is veel meer dan 1us, dus vandaar 8 NOPs + enkele instructies voor de pinchange. De 8 NOPs komt neer op 500ns met een 16Mhz clock. Als de interne 8Mhz clock van de ATMega gebruikt wordt is dit natuurlijk het dubbelen (dan moeten er NOPs weg).

De library PySerial is wel benodigd overigens. Simpel te installeren op Mac met:

code:

pip install pyserial

Bij het debuggen goed kijken wat de state machine precies wil, is niet netjes gedaan en eigenlijk een grote bende. Maar ja, misschien nog te fatsoeneren mochten we het op GitHub oid willen knallen. De rest van de code is redelijk recht toe recht aan, geen bijzondere zaken en lekker simpel gehouden.

Ben benieuwd of het een beetje draait. Zou leuk zijn als we al de goede richting in zitten.

LET OP: zojuist nog een klein foutje hersteld mbt pin 13 voor WRITE_EN define, dat moet de bitmask voor PB5 zijn

Ik heb "pip installed" pyserial, maar hij vindt nog steeds

code:

import serial

.
niet. Hoe configureer je dat ook weer?

[EDIT] never mind... al gevonden [/EDIT]

Ik wil met alle plezier mee testen om de boel op Github te krijgen. Ik kan morgenochtend (donderdag) of vrijdag vanaf de middag aan de gang.

[EDIT] De communicatie lijkt tot stand te worden gebracht. Morgen verder [/EDIT]

Gerard

Ain't no place like 127.0.0.1