Thursday, January 16, 2014

68k project: step III - execute some bytes by 68008 from RAM

[original article - http://xepb.org/dtz/68kavr.html ]
Well, to run program from RAM we should solder it in.

So, the Scheme 2:


XEPb.org is down again! Welcome on next week


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 are the tits is current photo of my board (20140118)
XEPb.org is down again! Welcome on next week


K1533LA3 = 74ALS00, K1533LL1 = 74ALS32, K555ID7 == 74LS138 (Soviet/russian chips)
The GCC source of AVR program for chapter III

68k project: step II - execute some bytes by 68008 taken from AVR, actually!

[original article - http://xepb.org/dtz/68kavr.html ]
The scheme for Running first program


XEPb.org is down again! Welcome in few days




The GCC source or AVR program


The result of running program:


(* is a clock tick , is a comment)
************************************************************************************************************************************
********************************************************************************************
Calling release reset
[Released reset]
**************************** clock after reset
INT: R Int happens when /DS goes low; R means that CPU is READING
State 0000***** "State 00" is some debug message, the other byte is actual byte
Releasing bus*** 5 clock changes /DS from low to high; 'Releasing bus' - MCU put data bus to high impedance.
INT: R
State 0000*****
Releasing bus***
INT: R
State 0000*****
Releasing bus***
INT: R
State 0008***** fed with 00000008; really the address does not matter, but it must be even, as you understand ;-) -
Releasing bus*** the first thing I've got was a trap leading write 14 bytes to somewhere
INT: R
State 0000*****
Releasing bus***
INT: R
State 0000*****
Releasing bus***
INT: R
State 0000*****
Releasing bus***
INT: R
State 00C0***** fed by stack pointer
Releasing bus***
INT: R
State 0020*****
Releasing bus***
INT: R
State 007C*****
Releasing bus*******
INT: R
State 0000*****
Releasing bus***
INT: R
State 0000*****
Releasing bus***
INT: R
State 0000*****
Releasing bus***
INT: R
State 0000***** fed with movea.l #0,A0
Releasing bus***
INT: R
State 0020*****
Releasing bus***
INT: R
State 003C*****
Releasing bus***
INT: R
State 00AA*****
Releasing bus***
INT: R
State 0055*****
Releasing bus***
INT: R
State 0033*****
Releasing bus***
INT: R
State 00CC***** fed with move.l #$aa5533cc,D0
Releasing bus***
INT: R
State 0020*****
Releasing bus***
INT: R
State 0080***** move.l D0,(A0)
Releasing bus***
INT: R
State 004E*****
Releasing bus***
INT: R
State 0071***** fed with NOP - that's prefetching
Releasing bus*****
INT: WAA******** Writing data! Whuuuuaaaaaauhuhhhh!
INT: W55********
INT: W33********
INT: WCC******
INT: R
State 004E*****
Releasing bus***
INT: R
State 0071*****
Releasing bus***
INT: R
State .....




So, we see that at least one command was executed by CPU

68k project: step I - execute some bytes by 68008 taken from AVR - the theory

[original article - http://xepb.org/dtz/68kavr.html ] Getting Reset, AVR (MCU) lowers RESET+HALT of 68008 (CPU) and begins to click clocks in main loop, which leads to the state called Boot Mode, and raises CPU's RESET+HALT some clicks after that.

Getting falling font of DS the MCU's INT0 is accured; while serving INT, main program waits until INT0 finished, so clock does not click, and there is no reason to play DTACK

INT0 feeds next byte of program to the CPU data bus (if CPU reads it), and leaves it there, returning from INT0 hanlder and making the main clock clicks. When main loop detects that DS is not active, it removes data from data bus.

So here it is:


/* Interrupt handling - DS gone low */
void ISR0()
{
if (RWline is UP) {
/* feed a byte to CPU */
writing_on_bus = 1;
write_on_bus(bytefeeder());
} else {
/* CPU is writing byte */
}
}


void main()
{
bootmode = 1;
reset_CPU(); reset_ticks = RESET_TICKS_VAL;
install_int0_handler(DS_line_does_down);
while(1)
{
click_clock();
/* may be some minimal delay, but CPU should be much faster then MCU*/
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;
}
}
}

}



While in boot mode, CPU should transfer some initial program to to memory,
then MCU should leave boot mode and send reset. After reset, CPU should execute the
main program already in RAM. It can later switch the clock source to run from a fast quartz.





2014016

Note 1. We have serial on ATmega, and you can use MAX232 or whatever you like
to connect it to COM port or USB.


Note 2. It is mentioned that interrups are used to determine /DS signal. Generally,
you do not need that because while CPU is clocked from MCU they are fully syncronized
(and when CPU will be clocked from external source there will be no way to talk with MCU
because it is slow). AVR interrupts are used because the code is clearer.