-
Notifications
You must be signed in to change notification settings - Fork 192
/
Copy pathmicrocode-eeprom-programmer.ino
204 lines (168 loc) · 5.73 KB
/
microcode-eeprom-programmer.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/**
* 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
#define WRITE_EN 13
#define HLT 0b1000000000000000 // Halt clock
#define MI 0b0100000000000000 // Memory address register in
#define RI 0b0010000000000000 // RAM data in
#define RO 0b0001000000000000 // RAM data out
#define IO 0b0000100000000000 // Instruction register out
#define II 0b0000010000000000 // Instruction register in
#define AI 0b0000001000000000 // A register in
#define AO 0b0000000100000000 // A register out
#define EO 0b0000000010000000 // ALU out
#define SU 0b0000000001000000 // ALU subtract
#define BI 0b0000000000100000 // B register in
#define OI 0b0000000000010000 // Output register in
#define CE 0b0000000000001000 // Program counter enable
#define CO 0b0000000000000100 // Program counter out
#define J 0b0000000000000010 // Jump (program counter in)
uint16_t data[] = {
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 0000 - NOP
MI|CO, RO|II|CE, IO|MI, RO|AI, 0, 0, 0, 0, // 0001 - LDA
MI|CO, RO|II|CE, IO|MI, RO|BI, EO|AI, 0, 0, 0, // 0010 - ADD
MI|CO, RO|II|CE, IO|MI, RO|BI, EO|AI|SU, 0, 0, 0, // 0011 - SUB
MI|CO, RO|II|CE, IO|MI, AO|RI, 0, 0, 0, 0, // 0100 - STA
MI|CO, RO|II|CE, IO|AI, 0, 0, 0, 0, 0, // 0101 - LDI
MI|CO, RO|II|CE, IO|J, 0, 0, 0, 0, 0, // 0110 - JMP
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 0111
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 1000
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 1001
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 1010
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 1011
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 1100
MI|CO, RO|II|CE, 0, 0, 0, 0, 0, 0, // 1101
MI|CO, RO|II|CE, AO|OI, 0, 0, 0, 0, 0, // 1110 - OUT
MI|CO, RO|II|CE, HLT, 0, 0, 0, 0, 0, // 1111 - HLT
};
/*
* Output the address bits and outputEnable signal using shift registers.
*/
void setAddress(int address, bool outputEnable) {
address = address & 0x7FFF;
byte msb = (address >> 8) | (outputEnable ? 0x00 : 0x80);
shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, msb);
byte lsb = address & 0xFF;
shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, lsb);
digitalWrite(SHIFT_LATCH, LOW);
digitalWrite(SHIFT_LATCH, HIGH);
digitalWrite(SHIFT_LATCH, LOW);
}
/*
* Read a byte from the EEPROM at the specified address.
*/
byte readEEPROM(int address) {
for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
pinMode(pin, INPUT);
}
setAddress(address, /*outputEnable*/ true);
byte data = 0x00;
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);
for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
pinMode(pin, OUTPUT);
}
for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
digitalWrite(pin, data & 1);
data = data >> 1;
}
digitalWrite(WRITE_EN, LOW);
delayMicroseconds(1);
digitalWrite(WRITE_EN, HIGH);
delay(10);
}
/**
* Clear out the entire EEPROM
*/
void eraseEEPROM()
{
Serial.println("Erasing EEPROM");
for (int address = 0x0000; address < 0x0800; address++) {
writeEEPROM(address, 0xff);
if (address % 0x40 == 0x00) {
Serial.print(".");
}
}
Serial.println("Erasing EEPROM -- Done.");
Serial.println();
}
void programEEPROM(byte data[], int length)
{
Serial.println("Programming EEPROM");
for (int address = 0x0000; address < length; address++) {
writeEEPROM(address, data[address]);
if (address % 0x40 == 0x00) {
Serial.print(".");
}
}
Serial.println(" Done.");
Serial.println();
}
void programEEPROM(uint16_t data[], int offset, int length, bool highByte)
{
Serial.println("Programming EEPROM");
for (int address = 0x0000; address < length; address++){
byte value = data[address] >> (highByte ? 8 : 0);
writeEEPROM(address + offset, value);
if (address % 0x40 == 0x00) {
Serial.print(".");
}
}
Serial.println(" Done.");
Serial.println();
}
/*
* Read the contents of the EEPROM and print them to the serial monitor.
*/
void printContents(int address) {
for (int base = 0x0000; base < 0x0100; base += 0x10) {
char buf[20];
sprintf(buf, "0x%04x: ", address + base);
Serial.print(buf);
for (int offset = 0; offset < 0x10; offset += 0x01) {
byte data = readEEPROM(address + base + offset);
sprintf(buf, "%02x ", data);
Serial.print(buf);
if (offset == 0x07) {
Serial.print(" ");
}
}
Serial.println();
}
Serial.println();
}
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);
// eraseEEPROM();
// Program data bytes
// Program the 8 high-order bits of microcode into the first 0x80 bytes of EEPROM
programEEPROM(data, 0x00, sizeof data / sizeof data[0], true);
// Program the 8 low-order bits of microcode into the second 0x80 bytes of EEPROM
programEEPROM(data, 0x80, sizeof data / sizeof data[0], false);
// Read and print out the contents of the EERPROM
Serial.println("Reading EEPROM");
printContents(0x0000);
}
void loop() {
// put your main code here, to run repeatedly:
}