Skip to content

Bootloader II

November 16, 2015

I spent several hours today working on the bootloader.  it more or less runs but it’s hard to test.  I have to load it into ram using the xmodem transfer in the monitor then quit the terminal program and start avrdude.  All my code is org’d to 8000 so the new subject overlays the front part of the loader with predictable results.  I need to work out a way of orging either the loader or the test code somewhere other than 8000.

 

I did get a blinker sketch running though so it does work, it’s just a matter of cleanup from here. The code really needs a complete rewrite but that can wait til it’s running successfully. Or, maybe not… It has to fit into the 2kleft in the boot rom so, if i start working toward that, I can re-org it at the same time, even if it stays in RAM for testing.

//ZMCLDR bootloader for the Z80 Olduino/Z
//based on olduinoII_ISPVF5_19
typedef unsigned char uint8_t;
#define HWVER 2
#define SWMAJ 5
#define SWMIN 0

// STK Definitions
#define STK_OK 0x10
#define STK_FAILED 0x11
#define STK_UNKNOWN 0x12
#define STK_INSYNC 0x14
#define STK_NOSYNC 0x15
#define CRC_EOP 0x20 //ok it is a space...
#include <stdio.h>
#include "olduino.h"
unsigned int timeoutstart, timeoutinterval=30000; //used to timeout the loader and start the olduino
int error=0;
int pmode=0;
unsigned int here; // address for reading and writing, set by 'U' command
unsigned char * z80where;//actual address to write
uint8_t buff[256]; // global block storage

#define beget16(addr) (*addr * 256 + *(addr+1) )
typedef struct param {
  uint8_t devicecode;
  uint8_t revision;
  uint8_t progtype;
  uint8_t parmode;
  uint8_t polling;
  uint8_t selftimed;
  uint8_t lockbytes;
  uint8_t fusebytes;
  int flashpoll;
  int eeprompoll;
  int pagesize;
  int eepromsize;
  int flashsize;
}
parameter;

parameter param;

void putstr(uint8_t * str){//print a string
	while(*str){//string is 0 terminated
		putcharncr(*str++);
	}
}

void setup() {
  delay(500);
  putstr("ZMC Bootloader V0 Nov 16*2\n");
  timeoutstart=millis();
}
void avrisp();
void runz80();
void start_pmode_1802();
void end_pmode_1802();
uint8_t write_flash_1802(int);
uint8_t read_page_1802(unsigned int);
void read_page();
void loop() {
  uint8_t char1802=0x55;
  if (Serialavailable()) {
    avrisp();
    timeoutstart=millis();
  }
  if(millis() - timeoutstart > timeoutinterval){
      runz80(); //run - does not return.
  }
}

uint8_t getch() {
  while(!Serialavailable());
  return Serialread();
}
void readbytes(int n) {
	int x;
  for (x = 0; x < n; x++) {
    buff[x] = getch(); //was Serialread();
  }
}


void empty_reply() {
  char gc=getch();
  if (CRC_EOP == gc) {
    putcharncr(STK_INSYNC);
    putcharncr(STK_OK);
  }
  else {
    putcharncr(STK_NOSYNC);
  }
}

void breply(uint8_t b) {
  if (CRC_EOP == getch()) {
    putcharncr(STK_INSYNC);
    putcharncr(b);
    putcharncr(STK_OK);
  }
  else {
    putcharncr(STK_NOSYNC);
  }
}

void get_version(uint8_t c) {
  switch(c) {
  case 0x80:
    breply(HWVER);
    break;
  case 0x81:
    breply(SWMAJ);
    break;
  case 0x82:
    breply(SWMIN);
    break;
  case 0x93:
    breply('S'); // serial programmer
    break;
  default:
    breply(0);
  }
}

void set_parameters() {
  // call this after reading paramter packet into buff[]
  param.devicecode = buff[0];
  param.revision = buff[1];
  param.progtype = buff[2];
  param.parmode = buff[3];
  param.polling = buff[4];
  param.selftimed = buff[5];
  param.lockbytes = buff[6];
  param.fusebytes = buff[7];
  param.flashpoll = buff[8];
  // ignore buff[9] (= buff[8])
  //getch(); // discard second value

  // WARNING: not sure about the byte order of the following
  // following are 16 bits (big endian)
  param.eeprompoll = beget16(&buff[10]);
  param.pagesize = beget16(&buff[12]);
  param.eepromsize = beget16(&buff[14]);

  // 32 bits flashsize (big endian)
  param.flashsize = buff[16] * 0x01000000
    + buff[17] * 0x00010000
    + buff[18] * 0x00000100
    + buff[19];

}

void start_pmode() {
  start_pmode_1802();
  //cout<<"entering program mode";
  pmode = 1;
}

void end_pmode() {
  end_pmode_1802();
  //cout<<"leaving program mode";
  pmode = 0;
}


uint8_t write_flash(int length) {
  write_flash_1802(length);
  return STK_OK;
}

void program_page() {
  char result = (char) STK_FAILED;
  int x ;
  char memtype;
  int length = 256 * getch() + getch(); //gets length 1-256
  if (length > 256) {
      putcharncr( STK_FAILED);
      return;
  }
  memtype = getch();
  for (x = 0; x < length; x++) {
    buff[x] = getch();
  }
  if (CRC_EOP == getch()) {
    putcharncr( STK_INSYNC);
    if (memtype == 'F') result = (char)write_flash(length);
    putcharncr(result);
  }
  else {
    putcharncr( STK_NOSYNC);
  }
}

void read_signature() {
  if (CRC_EOP != getch()) {
    putcharncr( STK_NOSYNC);
    return;
  }
  putcharncr( STK_INSYNC);
  #define sig_high 0x1e //dummy (code for part ATMEGA644P
  #define sig_middle 0x96 //device
  #define sig_low 0x0A //signature
  putcharncr( sig_high);
  putcharncr( sig_middle);
  putcharncr( sig_low);
  putcharncr( STK_OK);
}
void universal() {//15-01-13 this is being used to retrieve the signature
  int w;
  //uint8_t ch;

  for (w = 0; w < 4; w++) { //take the data
    buff[w] = getch();
  }
  if ((buff[0]==0x30)  && (buff[2]==0x00)){
    breply(sig_high);
  }
  else if ((buff[0]==0x30)  && (buff[2]==0x01)){
     breply(sig_middle);
  }
  else if ((buff[0]==0x30)  && (buff[2]==0x02)){
    breply(sig_low);
  }
  else{
    breply(STK_FAILED); //see if this gets a rise out of avrdude
  }
}
//////////////////////////////////////////
//////////////////////////////////////////



void read_page() {
  char result = (char)STK_FAILED;
  int length = 256 * getch() + getch();
  char memtype = getch();
  //cout<<"reading "<<length<<" bytes of "<<memtype<<" ";
  if (CRC_EOP != getch()) {
    putcharncr( STK_NOSYNC);
    return;
  }
  putcharncr( STK_INSYNC);
  if (memtype == 'F') result = read_page_1802(length);
  putcharncr(result);
  return;
}

////////////////////////////////////
////////////////////////////////////


void main(){
	setup();
	while(1){
		loop();
	}
}
#include "olduino.c"
#include "avrisp.c"
#include "ioz80.c"


void doitall();
void sethere_1802();
void avrisp() {
  uint8_t data, low, high, gc;
  uint8_t ch =getch();    //cout<<"<"<<_HEX(ch)<<" ";
  //printf("avrisp sees %hx\n",ch);
  switch (ch) {
  case '?': //debug
    doitall();
    break;
  case '!': //run
    putstr("!=run\n");
    runz80();
    break;
  case '0': // signon
  	//printf("0=signon\n");
    empty_reply();
    break;
  case '1':
    gc=getch(); //cout<<":"<<_HEX(gc)<<" ";
    if (gc == CRC_EOP) {
      putcharncr(STK_INSYNC);
      putstr("AVR ISP");
      putcharncr(STK_OK);
    }
    break;
  case 'A':
    gc=getch(); //cout<<":"<<_HEX(gc)<<" ";
    get_version(gc);
    break;
  case 'B':
    readbytes(20);
    set_parameters();
    empty_reply();
    break;
  case 'E': // extended parameters - ignore for now
    readbytes(5);
    empty_reply();
    break;

  case 'P':
    start_pmode();
    empty_reply();
    break;
  case 'U':
    here = getch() + 256 * getch();
    z80where=(unsigned char *)(here*2);
    //cout<<"here="<<_HEX(here);
    empty_reply();
    break;

  case 0x60: //STK_PROG_FLASH
    low = getch();
    high = getch();
    empty_reply();
    break;
  case 0x61: //STK_PROG_DATA
    data = getch();
    empty_reply();
    break;

  case 0x64: //STK_PROG_PAGE
    program_page();
    break;

  case 0x74: //STK_READ_PAGE
    read_page();
    break;

  case 'V':
    universal();
    break;
  case 'Q':
    error=0;
    end_pmode();
    empty_reply();
    //run1802();
    break;

  case 0x75: //STK_READ_SIGN
    read_signature();
    break;

  // expecting a command, not CRC_EOP
  // this is how we can get back in sync
  case CRC_EOP:
    putcharncr(STK_NOSYNC);
    break;

  // anything else we will return STK_UNKNOWN
  default:
    if (CRC_EOP == getch())
      putcharncr(STK_UNKNOWN);
    else
      putcharncr(STK_NOSYNC);
  }
  //printf("avrisp done\n");
}


/*
void busout(uint8_t t){ //put a byte on the bus
	//printf("\nbusout %hx\n",t);
}
uint8_t busin(){ //read a byte from the 1802
  uint8_t buschar=0x55;
	//printf("\nbusin with here=%x",here);

  return buschar;
}
*/
void runz80(){
  delay(2);
  putstr("\nrunZ80\n");
	while(1);
}
void domeall(){
 }

void doitall(){
  putstr("doing it all\n");
}
void start_pmode_1802() {
  //cout<<"entering program mode";
  pmode = 1;
}

void end_pmode_1802() {
  //cout<<"leaving program mode";
  pmode = 0;
}




uint8_t read_byte_1802() {//first try
  return * z80where;
}
uint8_t read_page_1802(unsigned int length) {//first try
  int x;
  for (x = 0; x < length; x+=1) {
    putcharncr(read_byte_1802());
  }
  return STK_OK;
}
void write_byte_1802(unsigned char data,unsigned char * where){ //write a byte to the 1802
	//printf("writing %hx at %x\n",data,where);
  *where=data;
}

uint8_t write_flash_1802(int length) {
  int x = 0;
  while (x < length) {
    write_byte_1802(buff[x++],z80where);
    z80where++;
  }
  return STK_OK;
}


Advertisements
Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: