Project

General

Profile

« Previous | Next » 

Revision 46

Added by markw over 11 years ago

First cut of reworked firmware. Just runs gunpowder charlie.atr drive emulation!

View differences:

firmware/Makefile
BASE = zpu-elf
CC = $(BASE)-gcc
LD = $(BASE)-gcc
AS = $(BASE)-as
CP = $(BASE)-objcopy
DUMP = $(BASE)-objdump
# we use mincrt0.s from here
STARTUP_DIR = .
# we fetch ROM prologue / epilogue from here
RTL_DIR = $(ZPUFLEXDIR)/RTL/
BUILD_DIR=zpu_obj
#MINSTARTUP_SRC = mincrt0.s
MINSTARTUP_SRC = mycrt0.s
MINSTARTUP_OBJ = $(patsubst $(STARTUP_DIR)/%.s,$(BUILD_DIR)/%.o,$(MINSTARTUP_SRC))
MAIN_PRJ = JustStartAtari
MAIN_SRC = main.c regs.c atari_drive_emulator.c pokey/uart.c hexdump.c printf/printf.c fat/pff_file.c fat/pff.c common/utils.c sd_direct/diskio_mmc.c sd_direct/spi.c sd_direct/mmc.c
#gcc -g -O0 -DLITTLE_ENDIAN test_drive.c atari_drive_emulator.c native/uart.c hexdump.c printf/printf.c fat/pff_file.c fat/pff.c common/utils.c native/diskio_image.c -I. -Iprintf -Ifat -Icommon
#MAIN_SRC = stuff.c
MAIN_OBJ = $(COMMON_OBJ) $(patsubst %.c,$(BUILD_DIR)/%.o,$(MAIN_SRC))
LINKMAP = ./standalone_simple.ld
# Commandline options for each tool.
#ZPUOPTS= -mno-poppcrel -mno-pushspadd -mno-callpcrel -mno-shortop -mno-neg # No-neg requires bugfixed toolchain
#Include everything -> need to include emulation rom...
ZPUOPTS =
CFLAGS = -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -Os $(ZPUOPTS) -DDISABLE_UART_RX
LFLAGS = -nostartfiles -Wl,--relax -g -Os
#LFLAGS = -nostartfiles -Os
# Our target.
all: $(BUILD_DIR) $(MAIN_PRJ).bin $(MAIN_PRJ).rpt
clean:
rm -f $(BUILD_DIR)/*.o *.hex *.elf *.map *.lst *.srec $(MAIN_PRJ).rom *~ */*.o *.bin
# Convert ELF binary to bin file.
%.bin: %.elf
$(CP) -O binary $< $@
%.rpt: %.elf
echo >$@ -n "End of code:\t"
$(DUMP) -x $< | grep >>$@ _romend
echo >>$@ -n "Start of BSS:\t"
$(DUMP) -x $< | grep >>$@ __bss_start__
echo >>$@ -n "End of BSS:\t"
$(DUMP) -x $< | grep >>$@ __bss_end__
cat $@
# Link - this produces an ELF binary.
$(MAIN_PRJ).elf: $(MINSTARTUP_OBJ) $(MAIN_OBJ)
$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
$(BUILD_DIR)/%.o: %.c Makefile
mkdir -p `dirname $@`
$(CC) $(CFLAGS) -o $@ -c $<
$(BUILD_DIR)/%.o: %.s
$(AS) -o $@ $<
$(BUILD_DIR)/%.o: $(STARTUP_DIR)/%.s
$(AS) -o $@ $<
$(BUILD_DIR):
mkdir $(BUILD_DIR)
firmware/actions.c
int bit_set(int var, int bit)
{
return (((1<<bit)&var)!=0);
}
void actions()
{
unsigned int i = 0;
//unsigned volatile char * store = 0xf00000; // SDRAM - fails!!
unsigned volatile char * store = 0xf80000; // SRAM...
unsigned volatile char * store2 = 0xfc0000; // custom chips...
// cold start (need to clear a few key locations to make OS cold start)
// file selector (where applicable)
// options (where applicable)
int keys = *zpu_in;
if (bit_set(keys,0))
{
coldstart();
}
else if (bit_set(keys,1))
{
set_pause_6502(1);
freeze();
menu_options();
restore();
set_pause_6502(0);
}
else if (bit_set(keys,2))
{
set_pause_6502(1);
freeze();
menu_fileselector();
coldstart();
}
}
void menu_options()
{
// title
// memory
// rom
// turbo
// disks
// exit/reboot
// simple state machine for menu, so I set up a small data structure then it just runs from that...
}
void menu_fileselector()
{
// title
// loads of stuff, filtered by type
// directories can be selected
// initial directory set, after that starts where it was left
}
firmware/atari_drive_emulator.c
#include "atari_drive_emulator.h"
#include "uart.h"
#include "pause.h"
#include "simplefile.h"
#include "printf.h"
#include "integer.h"
#define send_ACK() USART_Transmit_Byte('A');
#define send_NACK() USART_Transmit_Byte('N');
#define send_CMPL() USART_Transmit_Byte('C');
#define send_ERR() USART_Transmit_Byte('E');
/* BiboDos needs at least 50us delay before ACK */
#define DELAY_T2_MIN wait_us(100);
/* the QMEG OS needs at least 300usec delay between ACK and complete */
#define DELAY_T5_MIN wait_us(300);
/* QMEG OS 3 needs a delay of 150usec between complete and data */
#define DELAY_T3_PERIPH wait_us(150);
#define speedslow 0x28
#define speedfast 0x6
#define XEX_SECTOR_SIZE 128
#define MAX_DRIVES 4
struct SimpleFile * drives[MAX_DRIVES];
struct ATRHeader
{
u16 wMagic;
u16 wPars;
u16 wSecSize;
u08 btParsHigh;
u32 dwCRC;
} __attribute__((packed));
struct ATRHeader atr_header;
int speed;
int badcommandcount;
int commandcount;
int opendrive;
unsigned char atari_sector_buffer[256];
unsigned char get_checksum(unsigned char* buffer, u16 len);
#define TWOBYTESTOWORD(ptr,val) (*((u08*)(ptr)) = val&0xff);(*(1+(u08*)(ptr)) = (val>>8)&0xff);
void processCommand();
void USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(unsigned short len);
void clearAtariSectorBuffer()
{
int i=256;
while (--i)
atari_sector_buffer[i] = 0;
}
int offset;
int xex_loader;
int xex_size;
uint8_t boot_xex_loader[179] = {
0x72,0x02,0x5f,0x07,0xf8,0x07,0xa9,0x00,0x8d,0x04,0x03,0x8d,0x44,0x02,0xa9,0x07,
0x8d,0x05,0x03,0xa9,0x70,0x8d,0x0a,0x03,0xa9,0x01,0x8d,0x0b,0x03,0x85,0x09,0x60,
0x7d,0x8a,0x48,0x20,0x53,0xe4,0x88,0xd0,0xfa,0x68,0xaa,0x8c,0x8e,0x07,0xad,0x7d,
0x07,0xee,0x8e,0x07,0x60,0xa9,0x93,0x8d,0xe2,0x02,0xa9,0x07,0x8d,0xe3,0x02,0xa2,
0x02,0x20,0xda,0x07,0x95,0x43,0x20,0xda,0x07,0x95,0x44,0x35,0x43,0xc9,0xff,0xf0,
0xf0,0xca,0xca,0x10,0xec,0x30,0x06,0xe6,0x45,0xd0,0x02,0xe6,0x46,0x20,0xda,0x07,
0xa2,0x01,0x81,0x44,0xb5,0x45,0xd5,0x43,0xd0,0xed,0xca,0x10,0xf7,0x20,0xd2,0x07,
0x4c,0x94,0x07,0xa9,0x03,0x8d,0x0f,0xd2,0x6c,0xe2,0x02,0xad,0x8e,0x07,0xcd,0x7f,
0x07,0xd0,0xab,0xee,0x0a,0x03,0xd0,0x03,0xee,0x0b,0x03,0xad,0x7d,0x07,0x0d,0x7e,
0x07,0xd0,0x8e,0x20,0xd2,0x07,0x6c,0xe0,0x02,0x20,0xda,0x07,0x8d,0xe0,0x02,0x20,
0xda,0x07,0x8d,0xe1,0x02,0x2d,0xe0,0x02,0xc9,0xff,0xf0,0xed,0xa9,0x00,0x8d,0x8e,
0x07,0xf0,0x82 };
// relokacni tabulka neni potreba, meni se vsechny hodnoty 0x07
// (melo by byt PRESNE 20 vyskytu! pokud je jich vic, pak bacha!!!)
void byteswap(WORD * inw)
{
#ifndef LITTLE_ENDIAN
unsigned char * in = (unsigned char *)inw;
unsigned char temp = in[0];
in[0] = in[1];
in[1] = temp;
#endif
}
struct command
{
u08 deviceId;
u08 command;
u08 aux1;
u08 aux2;
u08 chksum;
} __attribute__((packed));
void getCommand(struct command * cmd)
{
int expchk;
//printf("Waiting for command\n");
//USART_Data_Ready();
while (0 == USART_Command_Line());
//printf("Init:");
//printf("%d",*zpu_sio);
USART_Init(speed+6);
//printf("%d",speed);
//printf("\n");
while (1 == USART_Command_Line())
{
actions();
}
cmd->deviceId = USART_Receive_Byte();
cmd->command = USART_Receive_Byte();
cmd->aux1 = USART_Receive_Byte();
cmd->aux2 = USART_Receive_Byte();
cmd->chksum = USART_Receive_Byte();
while (0 == USART_Command_Line())
{
actions();
}
printf("cmd:");
//printf("Gone high\n");
atari_sector_buffer[0] = cmd->deviceId;
atari_sector_buffer[1] = cmd->command;
atari_sector_buffer[2] = cmd->aux1;
atari_sector_buffer[3] = cmd->aux2;
expchk = get_checksum(&atari_sector_buffer[0],4);
//printf("Device id:");
printf("%d",cmd->deviceId);
//printf("\n");
//printf("command:");
printf("%d",cmd->command);
//printf("\n");
//printf("aux1:");
printf("%d",cmd->aux1);
//printf("\n");
//printf("aux2:");
printf("%d",cmd->aux2);
//printf("\n");
//printf("chksum:");
printf("%d",cmd->chksum);
printf("%d",expchk);
if (expchk!=cmd->chksum || USART_Framing_Error())
{
printf("ERR ");
//wait_us(1000000);
if (speed == speedslow)
{
speed = speedfast;
printf("SPDF");
printf("%d",speed);
}
else
{
speed = speedslow;
printf("SPDS");
printf("%d",speed);
}
}
printf("\n");
DELAY_T2_MIN;
}
int compare_ext(char const * filename, char const * ext)
{
int dot = 0;
while (1)
{
if (filename[dot] == '\0')
break;
if (filename[dot] != '.')
{
++dot;
continue;
}
if (filename[dot+1] == ext[0])
if (filename[dot+2] == ext[1])
if (filename[dot+3] == ext[2])
{
return 1;
break;
}
break;
}
return 0;
}
// Called whenever file changed
void set_drive_status(int driveNumber, struct SimpleFile * file)
{
int read = 0;
int xfd = 0;
drives[driveNumber] = 0;
if (!file) return;
// Read header
read = 0;
file_seek(file,0);
file_read(file,(unsigned char *)&atr_header, 16, &read);
if (read!=16)
{
printf("Could not read header\n");
return; //while(1);
}
byteswap(&atr_header.wMagic);
byteswap(&atr_header.wPars);
byteswap(&atr_header.wSecSize);
/*printf("\nHeader:");
printf("%d",atr_header.wMagic);
plotnext(toatarichar(' '));
printf("%d",atr_header.wPars);
plotnext(toatarichar(' '));
printf("%d",atr_header.wSecSize);
plotnext(toatarichar(' '));
printf("%d",atr_header.btParsHigh);
plotnext(toatarichar(' '));
printf("%d",atr_header.dwCRC);
printf("\n");
*/
xex_loader = 0;
xfd = compare_ext(file_name(file),"XFD") || compare_ext(file_name(file),"xfd");
if (xfd == 1)
{
printf("XFD ");
// build a fake atr header
offset = 0;
atr_header.wMagic = 0x296;
atr_header.wPars = file_size(file)/16;
atr_header.wSecSize = 0x80;
}
else if (atr_header.wMagic == 0xFFFF) // XEX
{
int i;
printf("XEX ");
offset = -256;
xex_loader = 1;
atr_header.wMagic = 0xffff;
xex_size = file_size(file);
atr_header.wPars = xex_size/16;
atr_header.wSecSize = XEX_SECTOR_SIZE;
}
else if (atr_header.wMagic == 0x296) // ATR
{
printf("ATR ");
offset = 16;
}
else
{
printf("Unknown file type");
return;
}
if (atr_header.wSecSize == 0x80)
{
if (atr_header.wPars>(720*128/16))
printf("MD ");
else
printf("SD ");
}
else if (atr_header.wSecSize == 0x100)
{
printf("DD ");
}
else if (atr_header.wSecSize < 0x100)
{
printf("XD ");
}
else
{
printf("BAD sector size");
return;
}
printf("%d",atr_header.wPars);
printf("0\n");
drives[driveNumber] = file;
}
void init_drive_emulator()
{
int i;
commandcount = 0;
badcommandcount = 0;
opendrive = -1;
speed = speedslow;
USART_Init(speed+6);
for (i=0; i!=MAX_DRIVES; ++i)
{
drives[i] = 0;
}
}
void run_drive_emulator()
{
while (1)
{
processCommand();
actions();
}
}
/////////////////////////
void processCommand()
{
struct command command;
getCommand(&command);
++commandcount;
/*FIXME if (commandcount==4 && (4==(4&(*zpu_switches))))
{
printf("Paused\n");
pause_6502(1);
while(1);
}*/
/*if (badcommandcount==8)
{
printf("Stuck?\n");
pause_6502(1);
while(1);
}*/
if (command.deviceId >= 0x31 && command.deviceId < 0x34)
{
int sent = 0;
int drive = 0;
struct SimpleFile * file = 0;
drive = command.deviceId&0xf -1;
printf("Drive:");
printf("%d",drive);
if (drive!=opendrive)
{
if (drive<MAX_DRIVES)
{
opendrive = drive;
}
}
if (drive<0 || !drives[drive])
{
//USART_Transmit_Mode();
//send_NACK();
//USART_Wait_Transmit_Complete();
//wait_us(100); // Wait for transmission to complete - Pokey bug, gets stuck active...
//USART_Receive_Mode();
printf("Drive not present");
return;
}
file = drives[opendrive];
switch (command.command)
{
case 0x3f:
{
printf("Speed:");
int sector = ((int)command.aux1) + (((int)command.aux2&0x7f)<<8);
USART_Transmit_Mode();
send_ACK();
clearAtariSectorBuffer();
atari_sector_buffer[0] = speedfast;
hexdump_pure(atari_sector_buffer,1);
USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(1);
sent = 1;
if (sector == 0)
{
speed = speedfast;
printf("SPDF");
printf("%d",speed);
}
else
{
speed = speedslow;
printf("SPDS");
printf("%d",speed);
}
}
case 0x53:
{
unsigned char status;
printf("Stat:");
USART_Transmit_Mode();
send_ACK();
clearAtariSectorBuffer();
status = 0x10; // Motor on;
status |= 0x08; // write protected; // no write support yet...
if (atr_header.wSecSize == 0x80) // normal sector size
{
if (atr_header.wPars>(720*128/16))
{
status |= 0x80; // medium density - or a strange one...
}
}
else
{
status |= 0x20; // 256 byte sectors
}
atari_sector_buffer[0] = status;
atari_sector_buffer[1] = 0xff;
atari_sector_buffer[2] = 0xe0;
atari_sector_buffer[3] = 0x0;
hexdump_pure(atari_sector_buffer,4); // Somehow with this...
USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(4);
sent = 1;
printf("%d",atari_sector_buffer[0]); // and this... The wrong checksum is sent!!
printf(":done\n");
}
break;
case 0x50: // write
case 0x57: // write with verify
default:
// TODO
//USART_Transmit_Mode();
//send_NACK();
//USART_Wait_Transmit_Complete();
//USART_Receive_Mode();
break;
case 0x52: // read
{
int sector = ((int)command.aux1) + (((int)command.aux2&0x7f)<<8);
int sectorSize = 0;
int read = 0;
int location =0;
USART_Transmit_Mode();
send_ACK();
printf("Sector:");
printf("%d",sector);
printf(":");
if(xex_loader) //n_sector>0 && //==0 se overuje hned na zacatku
{
//sektory xex bootloaderu, tj. 1 nebo 2
u08 i,b;
u08 *spt, *dpt;
int file_sectors;
//file_sectors se pouzije pro sektory $168 i $169 (optimalizace)
//zarovnano nahoru, tj. =(size+124)/125
file_sectors = ((xex_size+(u32)(XEX_SECTOR_SIZE-3-1))/((u32)XEX_SECTOR_SIZE-3));
printf("XEX ");
if (sector<=2)
{
printf("boot ");
spt= &boot_xex_loader[(u16)(sector-1)*((u16)XEX_SECTOR_SIZE)];
dpt= atari_sector_buffer;
i=XEX_SECTOR_SIZE;
do
{
b=*spt++;
//relokace bootloaderu z $0700 na jine misto
//TODO if (b==0x07) b+=bootloader_relocation;
*dpt++=b;
i--;
} while(i);
}
else
if(sector==0x168)
{
printf("numtobuffer ");
//vrati pocet sektoru diskety
//byty 1,2
goto set_number_of_sectors_to_buffer_1_2;
}
else
if(sector==0x169)
{
printf("name ");
//fatGetDirEntry(FileInfo.vDisk.file_index,5,0);
//fatGetDirEntry(FileInfo.vDisk.file_index,0); //ale musi to posunout o 5 bajtu doprava
{
u08 i,j;
for(i=j=0;i<8+3;i++)
{
/*if( ((xex_name[i]>='A' && xex_name[i]<='Z') ||
(xex_name[i]>='0' && xex_name[i]<='9')) )
{
//znak je pouzitelny na Atari
atari_sector_buffer[j]=xex_name[i];
j++;
}*/
if ( (i==7) || (i==8+2) )
{
for(;j<=i;j++) atari_sector_buffer[j]=' ';
}
}
//posune nazev z 0-10 na 5-15 (0-4 budou systemova adresarova data)
//musi pozpatku
for(i=15;i>=5;i--) atari_sector_buffer[i]=atari_sector_buffer[i-5];
//a pak uklidi cely zbytek tohoto sektoru
for(i=5+8+3;i<XEX_SECTOR_SIZE;i++)
atari_sector_buffer[i]=0x00;
}
//teprve ted muze pridat prvnich 5 bytu na zacatek nulte adresarove polozky (pred nazev)
//atari_sector_buffer[0]=0x42; //0
//jestlize soubor zasahuje do sektoru cislo 1024 a vic,
//status souboru je $46 misto standardniho $42
atari_sector_buffer[0]=(file_sectors>(0x400-0x171))? 0x46 : 0x42; //0
TWOBYTESTOWORD(atari_sector_buffer+3,0x0171); //3,4
set_number_of_sectors_to_buffer_1_2:
TWOBYTESTOWORD(atari_sector_buffer+1,file_sectors); //1,2
}
else
if(sector>=0x171)
{
printf("data ");
file_seek(file,((u32)sector-0x171)*((u32)XEX_SECTOR_SIZE-3));
file_read(file,&atari_sector_buffer[0], XEX_SECTOR_SIZE-3, &read);
if(read<(XEX_SECTOR_SIZE-3))
sector=0; //je to posledni sektor
else
sector++; //ukazatel na dalsi
atari_sector_buffer[XEX_SECTOR_SIZE-3]=((sector)>>8); //nejdriv HB !!!
atari_sector_buffer[XEX_SECTOR_SIZE-2]=((sector)&0xff); //pak DB!!! (je to HB,DB)
atari_sector_buffer[XEX_SECTOR_SIZE-1]=read;
}
printf(" sending\n");
sectorSize = XEX_SECTOR_SIZE;
}
else
{
location = offset;
if (sector>3)
{
sector-=4;
location += 128*3;
location += sector*atr_header.wSecSize;
sectorSize = atr_header.wSecSize;
}
else
{
location += 128*(sector-1);
sectorSize = 128;
}
printf("%d",location);
printf("\n");
file_seek(file,location);
file_read(file,&atari_sector_buffer[0], sectorSize, &read);
}
//topofscreen();
//hexdump_pure(atari_sector_buffer,sectorSize);
//printf("Sending\n");
USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(sectorSize);
sent = 1;
//pause_6502(1);
//hexdump_pure(0x10000+0x400,128);
unsigned char chksumreceive = 0; //get_checksum(0x10000+0x400, sectorSize);
printf(" receive:");
printf("%d",chksumreceive);
printf("\n");
//pause_6502(1);
//while(1);
}
break;
}
//wait_us(100); // Wait for transmission to complete - Pokey bug, gets stuck active...
if (sent)
USART_Wait_Transmit_Complete();
USART_Receive_Mode();
}
else
{
++badcommandcount;
}
}
unsigned char get_checksum(unsigned char* buffer, u16 len)
{
u16 i;
u08 sumo,sum;
sum=sumo=0;
for(i=0;i<len;i++)
{
sum+=buffer[i];
if(sum<sumo) sum++;
sumo = sum;
}
return sum;
}
void USART_Send_Buffer(unsigned char *buff, u16 len)
{
while(len>0) { USART_Transmit_Byte(*buff++); len--; }
}
void USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(unsigned short len)
{
u08 check_sum;
printf("(send:");
printf("%d",len);
DELAY_T5_MIN;
send_CMPL();
// Hias: changed to 100us so that Qmeg3 works again with the
// new bit-banging transmission code
DELAY_T3_PERIPH;
check_sum = 0;
USART_Send_Buffer(atari_sector_buffer,len);
// tx_checksum is updated by bit-banging USART_Transmit_Byte,
// so we can skip separate calculation
check_sum = get_checksum(atari_sector_buffer,len);
USART_Transmit_Byte(check_sum);
//hexdump_pure(atari_sector_buffer,len);
printf(":chk:");
printf("%d",check_sum);
printf(")");
}
firmware/atari_drive_emulator.h
#pragma once
// In principle the drive emulator itself just needs to have access to files from somewhere and then serves requests from the Atari.
// So it doesn't need to depend on fat, just needs a way of reading the specified 'file'
// So entry points are:
// i) Provide function ptr to: fetch data, check file size
// ii) Notify when disk has been changed/removed
// iii) Drive - called frequently so we can respond to commands received from Pokey
// To speak to the Atari we need:
// a) Command line
// b) Pokey
// Both these are mapped into zpu config regs
void actions(); // this is called whenever possible - should be quick
void init_drive_emulator();
void run_drive_emulator(); // Blocks. Pokey at its fastest is 6 cycles * 10 bits per byte. i.e. 60 cycles at 1.79MHz.
// To remove a disk, set file to null
// For a read-only disk, just have no write function!
struct SimpleFile;
void set_drive_status(int driveNumber, struct SimpleFile * file);
firmware/build
zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2 -DDISABLE_UART_RX -o zpu_obj/uart.o -c pokey/uart.c
zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2 -DDISABLE_UART_RX -o zpu_obj/hexdump.o -c hexdump.c
zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2 -DDISABLE_UART_RX -o zpu_obj/printf.o -c printf/printf.c
zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2 -DDISABLE_UART_RX -o zpu_obj/pff_file.o -c fat/pff_file.c
zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2 -DDISABLE_UART_RX -o zpu_obj/pff.o -c fat/pff.c
zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2 -DDISABLE_UART_RX -o zpu_obj/utils.o -c common/utils.c
zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2 -DDISABLE_UART_RX -o zpu_obj/diskio_mmc.o -c diskio_mmc.c
zpu-elf-gcc -nostartfiles -Wl,--relax -g -Os -T ./standalone_simple.ld -o JustStartAtari.elf mycrt0.s zpu_obj/main.o zpu_obj/regs.o zpu_obj/atari_drive_emulator.o zpu_obj/pokey/uart.o zpu_obj/hexdump.o zpu_obj/printf/printf.o zpu_obj/fat/pff_file.o zpu_obj/fat/pff.o zpu_obj/common/utils.o zpu_obj/diskio_mmc.o
zpu-elf-objcopy -O binary JustStartAtari.elf JustStartAtari.bin
echo >JustStartAtari.rpt -n "End of code:\t"
zpu-elf-objdump -x JustStartAtari.elf | grep >>JustStartAtari.rpt _romend
echo >>JustStartAtari.rpt -n "Start of BSS:\t"
zpu-elf-objdump -x JustStartAtari.elf | grep >>JustStartAtari.rpt __bss_start__
echo >>JustStartAtari.rpt -n "End of BSS:\t"
zpu-elf-objdump -x JustStartAtari.elf | grep >>JustStartAtari.rpt __bss_end__
cat JustStartAtari.rpt
firmware/build_native_drive
gcc -g -O0 -DLITTLE_ENDIAN test_drive.c atari_drive_emulator.c native/uart.c hexdump.c printf/printf.c fat/pff_file.c fat/pff.c common/utils.c native/diskio_image.c -I. -Iprintf -Ifat -Icommon
firmware/build_native_file_test
gcc -g -O0 test_file.c fat/pff_file.c fat/pff.c common/utils.c native/diskio_image.c -I. -Ifat -Icommon
firmware/hexdump.c
#include "hexdump.h"
#include "printf.h"
void hexdump_pure(void const * str, int length)
{
for (;length>0;--length)
{
unsigned char val= *(unsigned char *)str++;
printf("%02x",val);
}
}
firmware/build_native_joystick
gcc -g -O0 test_joy.c joystick.c native/regs.c -I.
firmware/common/integer.h
#ifndef _INTEGER
#define _INTEGER
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
typedef unsigned char u08;
typedef unsigned char uint8_t;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
typedef unsigned short u16;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
typedef unsigned int u32;
#define EEMEM
#endif
firmware/common/utils.c
int strcmp(char const * a, char const * b)
{
while (*a || *b)
{
if (*a<*b)
return -1;
else if (*a>*b)
return 1;
++a;
++b;
}
return 0;
}
void strcpy(char * dest, char const * src)
{
while (*dest++=*src++);
}
int strlen(char const * a)
{
int count;
for (count=0; *a; ++a,++count);
return count;
}
firmware/joystick.h
#pragma once
struct joystick_status
{
char x_;
char y_;
char fire_;
};
enum JoyWait {WAIT_QUIET, WAIT_FIRE, WAIT_MOVE, WAIT_EITHER};
void joystick_poll(struct joystick_status * status);
void joystick_wait(struct joystick_status * status, enum JoyWait waitFor);
firmware/mif_file_stuff/rom_prologue.vhd
DEPTH = 4096; % Memory depth and width are required %
% DEPTH is the number of addresses %
WIDTH = 32; % WIDTH is the number of bits of data per word %
% DEPTH and WIDTH should be entered as decimal numbers %
ADDRESS_RADIX = HEX; % Address and value radixes are required %
DATA_RADIX = HEX; % Enter BIN, DEC, HEX, OCT, or UNS; unless %
% otherwise specified, radixes = HEX %
-- Specify values for addresses, which can be single address or range
CONTENT
BEGIN
firmware/mycrt0.s
/* Startup code for ZPU
Copyright (C) 2005 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file with other programs, and to distribute
those programs without any restriction coming from the use of this
file. (The General Public License restrictions do apply in other
respects; for example, they cover modification of the file, and
distribution when not linked into another program.)
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
.file "mincrt0.S"
/* Minimal startup code, usable where the core is complete enough not to require emulated instructions */
.section ".fixed_vectors","ax"
; KLUDGE!!! we remove the executable bit to avoid relaxation
.section ".fixed_vectors","a"
.macro fixedim value
im \value
.endm
.macro jmp address
fixedim \address
poppc
.endm
.macro fast_neg
not
im 1
add
.endm
.macro mult1bit
; create mask of lowest bit in A
loadsp 8 ; A
im 1
and
im -1
add
not
loadsp 8 ; B
and
add ; accumulate in C
; shift B left 1 bit
loadsp 4 ; B
addsp 0
storesp 8 ; B
; shift A right 1 bit
loadsp 8 ; A
flip
addsp 0
flip
storesp 12 ; A
.endm
.macro cimpl funcname
; save R0
im _memreg
load
; save R1
im _memreg+4
load
; save R2
im _memreg+8
load
loadsp 20
loadsp 20
fixedim \funcname
call
; destroy arguments on stack
storesp 0
storesp 0
im _memreg
load
; poke the result into the right slot
storesp 24
; restore R2
im _memreg+8
store
; restore R1
im _memreg+4
store
; restore r0
im _memreg
store
storesp 4
poppc
.endm
.globl _start
_start:
jmp _premain
/* vectors */
/* instruction emulation code */
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
# opcode 34
# offset 0x0000 0040
.balign 32,0
_loadh:
loadsp 4
; by not masking out bit 0, we cause a memory access error
; on unaligned access
im ~0x2
and
load
; mult 8
loadsp 8
im 3
and
fast_neg
im 2
add
im 3
ashiftleft
; shift right addr&3 * 8
lshiftright
im 0xffff
and
storesp 8
poppc
# opcode 35
# offset 0x0000 0060
.balign 32,0
_storeh:
loadsp 4
; by not masking out bit 0, we cause a memory access error
; on unaligned access
im ~0x2
and
load
; mask
im 0xffff
loadsp 12
im 3
and
fast_neg
im 2
add
im 3
ashiftleft
ashiftleft
not
and
loadsp 12
im 0xffff
nop
fixedim _storehtail
poppc
# opcode 36
# offset 0x0000 0080
.balign 32,0
_lessthan:
loadsp 8
fast_neg
loadsp 8
add
; DANGER!!!!
; 0x80000000 will overflow when negated, so we need to mask
; the result above with the compare positive to negative
; number case
loadsp 12
loadsp 12
not
and
not
and
; handle case where we are comparing a negative number
; and positve number. This can underflow. E.g. consider 0x8000000 < 0x1000
loadsp 12
not
loadsp 12
and
or
flip
im 1
and
storesp 12
storesp 4
poppc
# opcode 37
# offset 0x0000 00a0
.balign 32,0
_lessthanorequal:
loadsp 8
loadsp 8
lessthan
loadsp 12
loadsp 12
eq
or
storesp 12
storesp 4
poppc
# opcode 38
# offset 0x0000 00c0
.balign 32,0
_ulessthan:
; fish up arguments
loadsp 4
loadsp 12
/* low: -1 if low bit dif is negative 0 otherwise: neg (not x&1 and (y&1))
x&1 y&1 neg (not x&1 and (y&1))
1 1 0
1 0 0
0 1 -1
0 0 0
*/
loadsp 4
not
loadsp 4
and
im 1
and
neg
/* high: upper 31-bit diff is only wrong when diff is 0 and low=-1
high=x>>1 - y>>1 + low
extremes
0000 - 1111:
low= neg(not 0 and 1) = 1111 (-1)
high=000+ neg(111) +low = 000 + 1001 + low = 1000
OK
1111 - 0000
low=neg(not 1 and 0) = 0
high=111+neg(000) + low = 0111
OK
*/
loadsp 8
flip
addsp 0
flip
loadsp 8
flip
addsp 0
flip
sub
; if they are equal, then the last bit decides...
add
/* test if negative: result = flip(diff) & 1 */
flip
im 1
and
; destroy a&b which are on stack
storesp 4
storesp 4
storesp 12
storesp 4
poppc
# opcode 39
# offset 0x0000 00e0
.balign 32,0
_ulessthanorequal:
loadsp 8
loadsp 8
ulessthan
loadsp 12
loadsp 12
eq
or
storesp 12
storesp 4
poppc
# opcode 40
# offset 0x0000 0100
.balign 32,0
.globl _swap
_swap:
breakpoint ; tbd
# opcode 41
# offset 0x0000 0120
.balign 32,0
_slowmult:
im _slowmultImpl
poppc
# opcode 42
# offset 0x0000 0140
.balign 32,0
_lshiftright:
loadsp 8
flip
loadsp 8
ashiftleft
flip
storesp 12
storesp 4
poppc
# opcode 43
# offset 0x0000 0160
.balign 32,0
_ashiftleft:
loadsp 8
loadsp 8
im 0x1f
and
fast_neg
im _ashiftleftEnd
add
poppc
# opcode 44
# offset 0x0000 0180
.balign 32,0
_ashiftright:
loadsp 8
loadsp 8
lshiftright
; handle signed value
im -1
loadsp 12
im 0x1f
and
lshiftright
not ; now we have an integer on the stack with the signed
; bits in the right position
; mask these bits with the signed bit.
loadsp 16
not
flip
im 1
and
im -1
add
and
; stuff in the signed bits...
or
; store result into correct stack slot
storesp 12
; move up return value
storesp 4
poppc
# opcode 45
# offset 0x0000 01a0
.balign 32,0
_call:
; fn
loadsp 4
; return address
loadsp 4
; store return address
storesp 12
; fn to call
storesp 4
pushsp ; flush internal stack
popsp
poppc
_storehtail:
and
loadsp 12
im 3
and
fast_neg
im 2
add
im 3
ashiftleft
nop
ashiftleft
or
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff