Skip to content
Tags

,

Bootloader

November 15, 2015

In a burst of misguided enthusiasm I am adapting an avr bootloader for the Z80. It actually started out as an ISP programmer that ran on arduino to program another avr. I adapted it for the original 1802 olduino where it runs on the onboard AVR and stuffs bytes into the 1802’s memory.

For olduino/z it’s going to become part of the monitor so probably in assembly language at the back of the ROM but to start with i’m migrating the C code and running it in RAM.

So Far I’ve recompiled it with SDCC and made what i think are the needed modifications. It’s over 4K at the moment but i’m not too worried.

The biggest conversion problems were mechanical like where i was using streaming(cout << whatever becomes printf(…) and c not allowing variable declarations after the start of a module. Also, I had to be careful about my function declarations where the arduino ide takes care of a lot of that stuff.

//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=20000; //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 setup() {
delay(2000);
printf("ZMC Bootloader V0 here\n");

}
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 Serial.read();
}
}

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

void breply(uint8_t b) {
if (CRC_EOP == getch()) {
putchar(STK_INSYNC);
putchar(b);
putchar(STK_OK);
}
else {
putchar(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) {
putchar( STK_FAILED);
return;
}
memtype = getch();
for (x = 0; x < length; x++) {
buff[x] = getch();
}
if (CRC_EOP == getch()) {
putchar( STK_INSYNC);
if (memtype == 'F') result = (char)write_flash(length);
putchar(result);
}
else {
putchar( STK_NOSYNC);
}
}

void read_signature() {
if (CRC_EOP != getch()) {
putchar( STK_NOSYNC);
return;
}
putchar( STK_INSYNC);
#define sig_high 0x1e //dummy (code for part ATMEGA644P
#define sig_middle 0x96 //device
#define sig_low 0x0A //signature
putchar( sig_high);
putchar( sig_middle);
putchar( sig_low);
putchar( 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()) {
putchar( STK_NOSYNC);
return;
}
putchar( STK_INSYNC);
if (memtype == 'F') result = read_page_1802(length);
putchar(result);
return;
}

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

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

//**AVRISP.C follows
void doitall();
void sethere_1802();
void avrisp() {
uint8_t data, low, high, gc;
uint8_t ch =getch(); //cout<<"<"<<_HEX(ch)<<" ";
switch (ch) {
case '?': //debug
doitall();
break;
case '!': //run
printf("!=run\n");
runz80();
break;
case '0': // signon
empty_reply();
break;
case '1':
gc=getch(); //cout<<":"<<_HEX(gc)<<" ";
if (gc == CRC_EOP) {
putchar(STK_INSYNC);
printf("AVR ISP");
putchar(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();
sethere_1802();
//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:
putchar(STK_NOSYNC);
break;

// anything else we will return STK_UNKNOWN
default:
if (CRC_EOP == getch())
putchar(STK_UNKNOWN);
else
putchar(STK_NOSYNC);
}
}
//ioz80.c follows
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);
printf("\nrunZ80(%u)\n",timeoutinterval);
while(1);
}
void domeall(){
}

void doitall(){
printf("doing it all\n");
}
void sethere_1802(){
z80where=(unsigned char *)here;
}
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) {
putchar(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

From → Uncategorized

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: