Questione puntatori su sistema a 8 bit.

di il
2 risposte

Questione puntatori su sistema a 8 bit.

Salve a tutti mi sono appena iscritto al forum e vi porgo i miei saluti, vengo al mio problema:

Ho come hobby l'elettronica e ho realizzato una motherboard con lo Z80 presentata in questo sito:
http://www.allthingsmicro.com/index.php/projects/20-z80-based-computer

Su questa scheda ho imparato da autodidatta a programmare in C, ho costruito una piccola interfaccia di espansione sopra la quale ho montato una compactflash e mi sono messo pian piano a scrivere prima le routines per accedere alla CF a basso livello, poi ho scritto le routines per creare e accedere a un filesystem che ho inventato di testa mia, poi ho scritto qualche piccolo programma, CD ... CAT ... LS ... Rename e un programmino che mi permette di fare l'upload di un file dal PC al filesystem dello Z80 attraverso la porta seriale, tutto funziona finche' lo eseguo dalla ram..

Siccome ero a buon punto con la struttura delle mie funzioni per usare il filesystem ho comprato su ebay un programmatore di eeprom tutto mio per poter riscrivere il mio bios, ho preso i sorgenti del monitor originale della scheda, quello fatto da "allthingsmicro" e ho pensato che visto era gia' in mini interprete dei comandi mi bastava includere i miei file .h per aggiungere tutte le varie funzioni, ricompilare e flasshare la eeprom.

Ho incluso il file con le funzioni base di i/o e ho provato a far fare al bios il semplice init dell'hardware, il compilatore (Z88DK) compila correttamente il sorgente, ma la scheda di blocca non appena tenta di avviare la ma funzione.

Ho guardanto un po' il codice binario generato e' penso di aver intuito il problema ma non so come risolverlo, il problema, per fare un'esempio e' questo:

int loop_busy()
do {
stato = inp(cfreg7);
} while (stato > 128);

Dove "stato" e' un "unsigned char" dichiarato all'inizio del sorgente, il compilatore compila il codice ma non tiene presente che l'area di memoria sotto i primi 32k e' ROM, quidi "stato" punta ad un'area della ROM e si blocca tutto perche' non puo' scriverci.

Credo di aver capito che devo spostare le variabili delle mie funzioni in un'indirizzo che cade nella RAM, ho letto qualcosa ma non ottengo i risultati che mi aspetto, ad esempio se faccio:

unsigned char stato = &0x8000; /* 0x8000 e' il primo indirizzo della ram*/

il compilatore mi dice invalid address, i vorrei memorizzare le variabili del mio programma in posizioni fisse ben precise della ram di sistema, qualcuno mi sa aiutare ?

Questo e' il codice del monitor che sto cercando di modificare:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mk2/mk2.h>
#include <mk2/vt100.h>
#include <mk2/crc16.h>
#include <mk2/xmodem.h>
#include <cf-io.h>

#define CLS		1
#define LOAD	2
#define HELP	3
#define RUN		4
#define prompt "\n\rZ80>"
#define hwname "Z80 Motherboard MK3 RomOS v1.0\n\r"

#define RAM_LENGTH	29184										/*29184 Bytes (28K) of avaliable RAM for user applications*/

void SetupHomeScreen(void);
char *mk2strtok(unsigned char *s1,unsigned char *s2);
int CommandIndex(char *Cmd);

extern unsigned char *strtokt;
extern char *RAM_Start @ 32768;

main()

{	
char CmdBuffer[50];
unsigned char RX;
char *Cmd = NULL;
char *Arg = NULL;
int LoadedApp=0;

int Ptr = 0;
int st;

	InitSerialConsole();										/*Must do this to use serial portA as console*/
	SetupHomeScreen();											/*Clear the screen,set the colours etc*/
	/*cf_init();*/

	while(1) {													/*loop forever*/
		Ptr = 0;
		Cmd = NULL;
		do {
			RX = getchar();										/*wait for a character from keyboard*/
			switch (RX) {
				case 8:											/*do we have a backspace*/
				case 127:										/*do we have a delete*/
					if(Ptr != 0) {								/*if its not the first char*/
						Ptr--;									/*move the command pointer back one*/
						CursorLeft(((int*)1));					/*move the cursor back on the VT100*/
						putchar(32);							/*wipe out the character with a space*/
						CursorLeft(((int*)1));					/*finally move the cursor back again*/
					}
					break;
				case 10:										/*do we have a cr*/
				case 13:										/*do we have a lf*/
					if(Ptr==0) {
						printf(prompt);
					} else {
						CmdBuffer[Ptr++] = '\0';				/*command entered so terminate the command string*/
					}
					break;
				default:										/*everything else*/
					if(Ptr == 49) {								/*is our command string getting to big for buffer 254?*/
						putchar(7);								/*yes send a bell*/
						Ptr--;									/*move the command pointer back one*/
						CursorLeft(((int*)1));					/*move the cursor back on the VT100*/
						putchar(32);  							/*wipe out the character with a space*/
						CursorLeft(((int*)1));					/*finally move the cursor back again*/
					}
					CmdBuffer[Ptr++] = RX;						/*add the char to the command buffer and add one to the command pointer*/
					putchar(RX);								/*echo it back*/
			}

		} while ((RX != 10 && RX != 13) || Ptr==0);				/*if we have a cr or lf exit*/

		Cmd = mk2strtok(CmdBuffer," ");							/*our syntax is command[ ]args[ ]args[ ]command[ ]args[ ]...pull each out using space as token*/
		while(Cmd != NULL) {
			switch(CommandIndex(Cmd)) {							/*get a command number so we can switch case*/
				case CLS:
					SetupHomeScreen();
					break;

				case LOAD:
						printf ("\n\rSend data using the xmodem protocol...\n\r");
						st = XModemReceive(&RAM_Start, RAM_LENGTH);
						switch(st) {
							case -1:
								printf("\n\rXmodem Error - Cancelled By Remote",prompt);
								break;
							case -2:
								printf("\n\rXmodem Error - Sync Error",prompt);
								break;
							case -3:
								printf("\n\rXmodem Error - Max Retry",prompt);
								break;
							default:
								LoadedApp=1;
								printf("\n\rXmodem successfully received %d bytes", st);
								printf("\n\rPress anykey to run your application\n\r");
								getchar();
								#asm
									call $8000
								#endasm
								Locate(((int*)0),((int*)24));
								printf("Press anykey to return to bios");
								getchar();
								SetupHomeScreen();
								break;
						}
					break;

				case HELP:
					printf("\n\rRecognised commands...\n\r\n\rcls\n\rload\n\rhelp\n\rrun\n\r");
					printf(prompt);
					break;

				case RUN:
					if(LoadedApp==1) {
						#asm
							call $8000
						#endasm
						Locate(((int*)0),((int*)24));
						printf("Press anykey to return to bios");
						getchar();
						SetupHomeScreen();
					}
					else {
						printf("\n\rNo Application Loaded",prompt);
					}
					break;

				default:
					printf("\n\r'%s' is not recognized as an command or program name",prompt,Cmd);
					break;
			}
			Cmd = mk2strtok(NULL," ");
		}
	}
}

/*
 * CommandIndex
 * Returns a interger value for a command string
 *
 */

int CommandIndex(char *Cmd)

{
	if(strcmp(Cmd,"cls")==0) return CLS;
	if(strcmp(Cmd,"load")==0) return LOAD;
	if(strcmp(Cmd,"help")==0) return HELP;
	if(strcmp(Cmd,"run")==0) return RUN;
	return -1;
}

/*
 * strtok for mk2
 * Uses Ram as temp storage not program space
 *
 */

char *mk2strtok(unsigned char *s1,unsigned char *s2)

{
  if(s1!=NULL)
    strtokt=s1;
  else
    s1=strtokt;
  s1+=strspn(s1,s2);
  if(*s1=='\0')
    return NULL;
  strtokt=s1;
  strtokt+=strcspn(s1,s2);
  if(*strtokt!='\0')
    *strtokt++='\0';
  return s1;
}

/*
 * Setup the home screen
 *
 */

void SetupHomeScreen(void)

{
	Cls();
	SetVTAttrib(VTBGBlack);
	SetVTAttrib(VTFGGreen);
	printf(hwname);
	SetScroll(((int*)2),((int*)24));
	SetSmoothScroll();
	SetVTAttrib(VTFGWhite);
	Locate(((int*)0),((int*)24));
	printf(prompt);
}
Questo e' il codice della libreria di I/O a basso livello:
/* Funzioni basilari di I/O sulla CF  */

/* Definizione dei registri della CF */
#define cfreg0 0x08 /* dati letti o da scrivere sulla cf */
#define cfreg1 0x09 /* leggi errore setta features */
#define cfreg2 0x0a /* quanti settori vuoi leggere in una volta */
#define cfreg3 0x0b /* indirizzo settore 0-7 bit */
#define cfreg4 0x0c /* indirizzo settore 8-15 bit */
#define cfreg5 0x0d /* indirizzo settore 16-23 bit */
#define cfreg6 0x0e /* indirizzo settore 24-27 bit */
#define cfreg7 0x0f /* leggi stato scrivi comando */

/* altri registri */
unsigned char stato;
unsigned char io_dialog;
unsigned char io_uscita;
unsigned char output[2];
unsigned char ram_buff[512];

unsigned char cf_size_alto;
unsigned char cf_size_medio;
unsigned char cf_size_basso;
unsigned long cf_size;
unsigned long cf_size2;
unsigned int cf_io_contatore = 0;
unsigned char cf_io_8b_contatore = 0;
unsigned char hw_presence = 0;

unsigned long address32;
unsigned char addr0;
unsigned char addr1;
unsigned char addr2;
unsigned char addr3;

/* inizializza la CF a 8 BIT */
int cf_init()
{
	loop_busy();
	outp(cfreg1, 0x01); /* features 8 bit */
	loop_busy();
	outp(cfreg7, 0xef); /* set features */
	loop_busy();
	hw_check();
	if (hw_presence == 1) {
							printf("\n\rCF inizializzata\n\r");
							capacity_info();
						  }
	hw_error_status();
}

/* loop busy */
int loop_busy()
do  {
		stato = inp(cfreg7);
    } while (stato > 128);

/* loop cmd ready*/
int loop_cmd_ready()
do {
		stato = inp(cfreg7);
   } while (stato > 128);

/* loop data ready*/
int loop_ready()
do {
		stato = inp(cfreg7);
   } while (stato == 1);

/* carica un settore di 512byte nel buffer */   
int load_seek(unsigned long lba_addr)
{
		hw_error_status();
		LBA(lba_addr);
		cf_read_cmd();
		for(cf_io_contatore = 0; cf_io_contatore < 512; cf_io_contatore++) /* carica il settore in ram */
		{
			ram_buff[cf_io_contatore] = inp(cfreg0);
		}
		
}

/* scrive il buffer da 512byte in un settore */
int write_seek(unsigned long lba_addr)
{
	hw_error_status();
	LBA(lba_addr);
	cf_write_cmd();
	for(cf_io_contatore = 0; cf_io_contatore < 512; cf_io_contatore++)
	        {
		        outp(cfreg0, ram_buff[cf_io_contatore]);
		        loop_busy();
			}
}

/* Cancella via hardware il contenuto di un dato settore */
int erase_seek(unsigned long lba_addr)
{
	hw_error_status();
	LBA(lba_addr);
	cf_erase_cmd();
}

/* comando lettura */
int cf_read_cmd()
{
	set_size();
	loop_cmd_ready();
	outp(cfreg7, 0x20);
	loop_busy();
	loop_ready();
}

/* comando scrittura */
int cf_write_cmd()
{
	set_size();
	loop_cmd_ready();
	outp(cfreg7, 0x30);
	loop_busy();
	loop_ready();
}

/* comando erase */
int cf_erase_cmd()
{
	set_size();
	loop_cmd_ready();
	outp(cfreg7, 0xc0);
	loop_busy();
	loop_ready();
}

/* indirizzi*/
int LBA(unsigned long address32)
{
    addr3 = (address32 & 0xff000000UL) >> 24;
    addr2 = (address32 & 0x00ff0000UL) >> 16;
    addr1 = (address32 & 0x0000ff00UL) >>  8;
    addr0 = (address32 & 0x000000ffUL)      ;
    
	if (addr3 =! 0)
			{
				printf("CF Addressing Overflow !\n\r");
			}
	
	outp(cfreg3, addr0);
	loop_busy();	

	outp(cfreg4, addr1);
	loop_busy();	

	outp(cfreg5, addr2);
	loop_busy();	

	outp(cfreg6, 0xe0);
	loop_busy();	
}

/*Setta la dimensione di settore a 512byte*/
int set_size()
{
	outp(cfreg2, 0x01); /*dimensione settore di 512 byte*/
	loop_busy();
}

/*Legge la ID hardware e la carica nel buffer*/
int cf_id()
{
	loop_cmd_ready();
	outp(cfreg7, 0xec);
	loop_busy();
	for(cf_io_contatore = 0; cf_io_contatore < 512; cf_io_contatore++)
		{
			ram_buff[cf_io_contatore] = inp(cfreg0);
		}
}

/*Stabilisce la dimensione della CF*/
int get_capacity()
{
	cf_id();
	cf_size_alto=ram_buff[116];
	cf_size_medio=ram_buff[115];
	cf_size_basso=ram_buff[114];
	cf_size = (cf_size_alto*65536)+(cf_size_medio*256)+cf_size_basso;
}

int capacity_info()
{
	get_capacity();	
	printf("%ld settori - ", cf_size);
	cf_size2 = (cf_size*512)/1000000;
	printf("Capacita' %ldMB\n\r", cf_size2);
}

/*svuota il buffer*/
int clear_buff()
{
	for(cf_io_contatore = 0; cf_io_contatore < 512; cf_io_contatore++)
	    {
			ram_buff[cf_io_contatore] = 0;   
		}
}

/*verifica la presenza della CF nello slot*/
int hw_check()
{
	hw_presence = 0;
	clear_buff();
	cf_id();
	for(cf_io_contatore = 0; cf_io_contatore < 256; cf_io_contatore++)
	    {
			if (ram_buff[cf_io_contatore] != 0, ram_buff[cf_io_contatore] != 104)	{
																					hw_presence = 1;
										   											}
		}
}
/* hardware error message */
int hw_error_status()
if (hw_presence == 0) {
			printf("\n\rNessuna CF inserita! Spegni la scheda Z80\n\re inserisci una CF nello slot se vuoi\n\rutilizzare le funzioni di mass storage.\n\r");							
		      }

2 Risposte

  • Re: Questione puntatori su sistema a 8 bit.

    In genere é il linker che riloca correttamente le variabili, anche attraverso specifiche indicazioni di configurazione.
  • Re: Questione puntatori su sistema a 8 bit.

    Riporto la mappa di memoria dichiarata della scheda:
    8000H – FFFFH = SRAM (READ/WRITE)

    We have used the z88dk Z80 compiler to program our Z80 motherboard, see the tutorial creating a Z80 development environment here. the z88dk compiler kit allows you to define how your Z80 computer is laid out, so as a start we have defined our memory space as follows. We have given various address spaces for the compiler to use for global variables, malloc, balloc etc. These definitions are not fixed and you can change them as you see fit.

    8000h = Start of your application (this is the address the boot-loader will call when you upload a program).

    8000h - F200h = This is the program/application space, 28K.

    F200h = 256 bytes for interrupt vector table (mode 2).

    F300h = 1024 bytes for global variables.

    F700h = mk2strtok working variable (strtok uses a temporary variable and by default places this in the program space, we use this for the boot-loader).

    F701h = 512 bytes for malloc heap.

    F901h = 4 bytes used as malloc heap working variables.

    F905h = 512 bytes for balloc heap.

    FB05h = 1 bytes for balloc heap table.

    FB06h = 40 bytes used for stdio control block.

    FB2Dh = 2 bytes for integer seed.

    FB2Fh = 3 bytes used for exit() stack pointer.

    FB32h = 19 bytes used for floating point math.

    FB50h = 16 bytes for INT ISR.

    FB60h = 159 bytes for NMI ISR.

    FBFFh = 1024 bytes used for Stack.
    Ho fatto delle prove e senbra che se dichiaro dei char o degli int etc ci posso scrivere e posso rileggerli, segno che il compilatore sa metterli in ram, come dice la descrizione: F300h = 1024 bytes for global variables. Il blocco avviene quando cerco di scrivere in ram_buff che e' una stringa di 512 byte.. forse non c'e' spazio a sufficenza ? io vedo sempre che viene allocata nello spazio rom, nel binario c'e' un bel buco di 512zeri. Pensavo che forse potevo usare una di quelle 2 aree da 512 segnale per malloc e balloc ... qualche idea ?
Devi accedere o registrarti per scrivere nel forum
2 risposte