Well, to run program from RAM we should solder it in.
So, the Scheme 2:
First, note the 74138. It decodes higher adress lines. It's all clear with it. Also, that it clear that RAM should start on Addr 0h, so put the /A0000 line to /CE of RAM.
Look at Atmega. The most significant of the new connections is the /BOOTMODE line. It is used to inform RAM to behave the following way: when /BOOTMODE is active, CPU should read not from RAM, but from MCU. It is AND-NOTed with R/W, so when /BOOTMODE is active (0) and READ(1) happens, the output of 7400 leg 8 is not active (high). When /BOOTMODE is not active and READ goes high, the output of 7400/8 goes low, and, ORed with /DS, this is fed (as /MEMRD) to /OE pin of RAM.
7432 also ORs /DS and R//W to get /MEMWR.
Sure, we'll use ATmega as uart, so we should connect one of the lines from 74138 ORed with DS to one of ATmega's leg (again, as interrupt, while that's not absolutely needed). And add an address line (A1) to get two registers for read and for write.
It's all clear that one pair is read byte from line and write byte to line, the other read register is status saying "we have an byte in input" and "it's clear to send the next char". The extra writing register is a HEX output.
So here will be an algorythm (bold is new code):
/* Interrupt handling - DS gone low */
void ISR0()
{
if (RWline is UP) {
/* feed a byte to CPU */
writing_on_bus = 1;
b = bytefeeder();
if (b != -1)
{
write_on_bus(b);
} else { // The boot 68k program is ended!
bootmode = 0; /* and /BOOTMODE leg*/
reset_CPU();
/*optional*/ uninstall_IRQ_0_handler();
}
} else {
/* CPU is writing byte to memory*/
}
}
void ISR2(USART_RXC_vect) // Serial event: a char came from terminal to AVR
{
byte_came = byte_from_serial();
byte_in_rx_que = 0x02; // Flag to be ORed when we'll tell CPU the status
}
void ISR1() // interrupt happened on /AVRSERAIL goes low
{
if (RWline is UP)
{
/* CPU is reading from serial */
writing_on_bus = 1;
if (A2_line_is_up) // CPU reads status
{
write_on_bus (clear_to_send | byte_in_rx_que);
} else
{
write_on_bus(byte_came); // last recieved byte from serial
byte_in_rx_que = 0;
}
} else /*CPU is writing to bus*/
{
if (A2_line_is_up)
{
serial_send_hex(byte_from_data_bus());
} else
{
serial_send(byte_from_data_bus());
}
}
}
void main()
{
bootmode = 1; /* as well as /BOOTMODE leg */
byte_in_rx_que = 0; // No pending serial bytes
reset_CPU(); reset_ticks = RESET_TICKS_VAL;
install_int0_handler(DS_line_does_down);
install_int1_handler(AVRSERIAL_goes_down); // Both can be done when leaving bootmode
install_serial_rx_handler();
while(1)
{
click_clock();
if (reset_ticks > 0)
{
if (!(reset_ticks--))
{
release_reset_CPU(); // reset - up!
}
}
if (DS_line_got_high)
{
if (writing_on_bus) {
switch_data_bus_to_read_mode();
writing_on_bus = 0;
}
}
}
}
What do we feed to cpu, you may ask?
Here it is (in file bytefeeder.c):
uint8_t PROGMEM prologue[] = {
0x00,0x00,0x10,0x00 // 0 dc.l stack pointer
,0x00,0x00,0x00,0x08 // 0 dc.l start
,0x20,0x7C ,0x00,0x00,0x00,0x00 // 8 movea.l #0,A0
};
, then, in loop,
uint8_t PROGMEM program_loop_bytes[] = {
0x30, 0xFC, 0, 0, // move.w #XX,(A0)+
0x4e, 0x71 // NOP
};
, replacing zeroes by the bytes from the actual program. The trailing NOP is needed because 68008 prefetches one command before executing the prevous (as shown in Chapter II)
And here
K1533LA3 = 74ALS00, K1533LL1 = 74ALS32, K555ID7 == 74LS138 (Soviet/russian chips)
The GCC source of AVR program for chapter III