mirror of
https://github.com/equant/apple2idiot.git
synced 2024-06-16 12:29:27 +00:00
366 lines
9.8 KiB
C
366 lines
9.8 KiB
C
|
#ifdef BUILD_APPLE2
|
||
|
/**
|
||
|
* FujiNet CONFIG for #Apple2
|
||
|
*
|
||
|
* SmartPort MLI Routines
|
||
|
*/
|
||
|
|
||
|
#ifdef __INTELLISENSE__
|
||
|
// 18, expect closing parenthses - needed to use cc65 inline asm command with agruments.
|
||
|
#pragma diag_suppress 18
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#include "sp.h"
|
||
|
#include <conio.h>
|
||
|
#include <stdio.h>
|
||
|
#include <apple2.h>
|
||
|
#include <peekpoke.h>
|
||
|
|
||
|
#define SP_CMD_STATUS 0
|
||
|
#define SP_CMD_CONTROL 4
|
||
|
#define SP_CMD_OPEN 6
|
||
|
#define SP_CMD_CLOSE 7
|
||
|
#define SP_CMD_READ 8
|
||
|
#define SP_CMD_WRITE 9
|
||
|
#define SP_STATUS_PARAM_COUNT 3
|
||
|
#define SP_CONTROL_PARAM_COUNT 3
|
||
|
#define SP_OPEN_PARAM_COUNT 1
|
||
|
#define SP_CLOSE_PARAM_COUNT 1
|
||
|
#define SP_READ_PARAM_COUNT 4
|
||
|
#define SP_WRITE_PARAM_COUNT 4
|
||
|
|
||
|
// extern globals:
|
||
|
uint8_t sp_payload[1024];
|
||
|
uint16_t sp_count;
|
||
|
uint8_t sp_dest;
|
||
|
uint16_t sp_dispatch;
|
||
|
uint8_t sp_error;
|
||
|
|
||
|
static uint8_t sp_cmdlist[10];
|
||
|
static uint8_t sp_cmdlist_low, sp_cmdlist_high;
|
||
|
static uint8_t sp_err, sp_rtn_low, sp_rtn_high;
|
||
|
|
||
|
int8_t sp_status(uint8_t dest, uint8_t statcode)
|
||
|
{
|
||
|
sp_error = 0;
|
||
|
// build the command list
|
||
|
sp_cmdlist[0] = SP_STATUS_PARAM_COUNT;
|
||
|
sp_cmdlist[1] = dest; // set before calling sp_status();
|
||
|
sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
|
||
|
sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
|
||
|
sp_cmdlist[4] = statcode;
|
||
|
|
||
|
sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
|
||
|
sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;
|
||
|
|
||
|
|
||
|
// store cmd list
|
||
|
__asm__ volatile ("lda #%b", SP_CMD_STATUS);
|
||
|
__asm__ volatile ("sta %g", spCmd); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_low);
|
||
|
__asm__ volatile ("sta %g", spCmdListLow); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_high);
|
||
|
__asm__ volatile ("sta %g", spCmdListHigh); // store status command #
|
||
|
|
||
|
__asm__ volatile ("jsr $C50D"); // to do - find SP entry point using algorithm from firmware reference
|
||
|
spCmd:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListLow:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListHigh:
|
||
|
__asm__ volatile ("nop");
|
||
|
__asm__ volatile ("stx %v", sp_rtn_low);
|
||
|
__asm__ volatile ("sty %v", sp_rtn_high);
|
||
|
__asm__ volatile ("sta %v", sp_err);
|
||
|
|
||
|
sp_count = ((uint16_t)sp_rtn_high << 8) | (uint16_t)sp_rtn_low;
|
||
|
sp_error = sp_err;
|
||
|
return sp_err;
|
||
|
}
|
||
|
|
||
|
int8_t sp_control(uint8_t dest, uint8_t ctrlcode)
|
||
|
{
|
||
|
sp_error = 0;
|
||
|
// sp_dest = 5; // need to search
|
||
|
// build the command list
|
||
|
sp_cmdlist[0] = SP_CONTROL_PARAM_COUNT;
|
||
|
sp_cmdlist[1] = dest; // set before calling sp_status();
|
||
|
sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
|
||
|
sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
|
||
|
sp_cmdlist[4] = ctrlcode;
|
||
|
|
||
|
sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
|
||
|
sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;
|
||
|
|
||
|
// store cmd list
|
||
|
__asm__ volatile ("lda #%b", SP_CMD_CONTROL);
|
||
|
__asm__ volatile ("sta %g", spCmd); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_low);
|
||
|
__asm__ volatile ("sta %g", spCmdListLow); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_high);
|
||
|
__asm__ volatile ("sta %g", spCmdListHigh); // store status command #
|
||
|
|
||
|
__asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
|
||
|
spCmd:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListLow:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListHigh:
|
||
|
__asm__ volatile ("nop");
|
||
|
__asm__ volatile ("sta %v", sp_err);
|
||
|
sp_error = sp_err;
|
||
|
return sp_err;
|
||
|
}
|
||
|
|
||
|
int8_t sp_open(uint8_t dest)
|
||
|
{
|
||
|
sp_error = 0;
|
||
|
// sp_dest = 5; // need to search
|
||
|
// build the command list
|
||
|
sp_cmdlist[0] = SP_OPEN_PARAM_COUNT;
|
||
|
sp_cmdlist[1] = dest; // set before calling sp_status();
|
||
|
|
||
|
sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
|
||
|
sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;
|
||
|
|
||
|
// store cmd list
|
||
|
__asm__ volatile ("lda #%b", SP_CMD_OPEN);
|
||
|
__asm__ volatile ("sta %g", spCmd); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_low);
|
||
|
__asm__ volatile ("sta %g", spCmdListLow); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_high);
|
||
|
__asm__ volatile ("sta %g", spCmdListHigh); // store status command #
|
||
|
|
||
|
__asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
|
||
|
spCmd:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListLow:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListHigh:
|
||
|
__asm__ volatile ("nop");
|
||
|
__asm__ volatile ("sta %v", sp_err);
|
||
|
sp_error = sp_err;
|
||
|
return sp_err;
|
||
|
}
|
||
|
|
||
|
int8_t sp_close(uint8_t dest)
|
||
|
{
|
||
|
sp_error = 0;
|
||
|
// sp_dest = 5; // need to search
|
||
|
// build the command list
|
||
|
sp_cmdlist[0] = SP_CLOSE_PARAM_COUNT;
|
||
|
sp_cmdlist[1] = dest; // set before calling sp_status();
|
||
|
|
||
|
sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
|
||
|
sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;
|
||
|
|
||
|
// store cmd list
|
||
|
__asm__ volatile ("lda #%b", SP_CMD_CLOSE);
|
||
|
__asm__ volatile ("sta %g", spCmd); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_low);
|
||
|
__asm__ volatile ("sta %g", spCmdListLow); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_high);
|
||
|
__asm__ volatile ("sta %g", spCmdListHigh); // store status command #
|
||
|
|
||
|
__asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
|
||
|
spCmd:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListLow:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListHigh:
|
||
|
__asm__ volatile ("nop");
|
||
|
__asm__ volatile ("sta %v", sp_err);
|
||
|
sp_error = sp_err;
|
||
|
return sp_err;
|
||
|
}
|
||
|
|
||
|
int8_t sp_read(uint8_t dest, uint16_t len)
|
||
|
{
|
||
|
sp_error = 0;
|
||
|
// sp_dest = 5; // need to search
|
||
|
// build the command list
|
||
|
sp_cmdlist[0] = SP_READ_PARAM_COUNT;
|
||
|
sp_cmdlist[1] = dest; // set before calling sp_status();
|
||
|
sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
|
||
|
sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
|
||
|
sp_cmdlist[4] = len & 0xFF;
|
||
|
sp_cmdlist[5] = len >> 8;
|
||
|
|
||
|
sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
|
||
|
sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;
|
||
|
|
||
|
// store cmd list
|
||
|
__asm__ volatile ("lda #%b", SP_CMD_READ);
|
||
|
__asm__ volatile ("sta %g", spCmd); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_low);
|
||
|
__asm__ volatile ("sta %g", spCmdListLow); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_high);
|
||
|
__asm__ volatile ("sta %g", spCmdListHigh); // store status command #
|
||
|
|
||
|
__asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
|
||
|
spCmd:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListLow:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListHigh:
|
||
|
__asm__ volatile ("nop");
|
||
|
__asm__ volatile ("sta %v", sp_err);
|
||
|
sp_error = sp_err;
|
||
|
return sp_err;
|
||
|
}
|
||
|
|
||
|
int8_t sp_write(uint8_t dest, uint16_t len)
|
||
|
{
|
||
|
sp_error = 0;
|
||
|
// build the command list
|
||
|
sp_cmdlist[0] = SP_READ_PARAM_COUNT;
|
||
|
sp_cmdlist[1] = dest; // set before calling sp_status();
|
||
|
sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
|
||
|
sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
|
||
|
sp_cmdlist[4] = len & 0xFF;
|
||
|
sp_cmdlist[5] = len >> 8;
|
||
|
|
||
|
sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
|
||
|
sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;
|
||
|
|
||
|
// store cmd list
|
||
|
__asm__ volatile ("lda #%b", SP_CMD_WRITE);
|
||
|
__asm__ volatile ("sta %g", spCmd); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_low);
|
||
|
__asm__ volatile ("sta %g", spCmdListLow); // store status command #
|
||
|
__asm__ volatile ("lda %v", sp_cmdlist_high);
|
||
|
__asm__ volatile ("sta %g", spCmdListHigh); // store status command #
|
||
|
|
||
|
__asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
|
||
|
spCmd:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListLow:
|
||
|
__asm__ volatile ("nop");
|
||
|
spCmdListHigh:
|
||
|
__asm__ volatile ("nop");
|
||
|
__asm__ volatile ("sta %v", sp_err);
|
||
|
sp_error = sp_err;
|
||
|
return sp_err;
|
||
|
}
|
||
|
|
||
|
int8_t sp_find_fuji()
|
||
|
{
|
||
|
// const char fuji[9] = "THE_FUJI";
|
||
|
const char fuji[14] = "FUJINET_DISK_0";
|
||
|
const uint8_t fuji_len = sizeof(fuji);
|
||
|
int8_t err, num, i, j;
|
||
|
|
||
|
err = sp_status(0x00, 0x00); // get number of devices
|
||
|
if (err)
|
||
|
return -err;
|
||
|
num = sp_payload[0];
|
||
|
num++;
|
||
|
for (i = 1; i < num; i++)
|
||
|
{
|
||
|
//do
|
||
|
err = sp_status(i, 0x03); // get DIB
|
||
|
//while (err);
|
||
|
if (sp_payload[4] == fuji_len)
|
||
|
{
|
||
|
for (j = 0; j < fuji_len; j++)
|
||
|
if (fuji[j]!=sp_payload[5+j])
|
||
|
return 0;
|
||
|
sp_dest = i; // store the fuji unit #
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int8_t sp_find_network()
|
||
|
{
|
||
|
const char net[7] = "NETWORK";
|
||
|
const uint8_t net_len = sizeof(net);
|
||
|
int8_t err, num, i, j;
|
||
|
|
||
|
err = sp_status(0x00, 0x00); // get number of devices
|
||
|
|
||
|
if (err)
|
||
|
return -err;
|
||
|
|
||
|
num = sp_payload[0];
|
||
|
num+=2;
|
||
|
|
||
|
for (i = 1; i < num; i++)
|
||
|
{
|
||
|
err = sp_status(i, 0x03); // get DIB
|
||
|
|
||
|
if (sp_payload[4] == net_len)
|
||
|
{
|
||
|
for (j = 0; j < net_len; j++)
|
||
|
if (net[j]!=sp_payload[5+j])
|
||
|
return 0;
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
printf("NET NOT FOUND");
|
||
|
cgetc();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Apple // SmartPort routines for CC65
|
||
|
*
|
||
|
* @author Thomas Cherryhomes
|
||
|
* @email thom dot cherryhomes at gmail dot com
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Check for SmartPort presence
|
||
|
* @return slot #, or 0xFF if not present.
|
||
|
*/
|
||
|
uint8_t sp_find_slot(void)
|
||
|
{
|
||
|
uint8_t s=0;
|
||
|
|
||
|
for (s=7; s-- > 0;)
|
||
|
{
|
||
|
uint16_t a = 0xc000 + (s * 0x100);
|
||
|
if ((PEEK(a+1) == 0x20) &&
|
||
|
(PEEK(a+3) == 0x00) &&
|
||
|
(PEEK(a+5) == 0x03) &&
|
||
|
(PEEK(a+7) == 0x00))
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
// Did not find.
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return dispatch address for Smartport slot.
|
||
|
* @param s Slot # (1-7)
|
||
|
* @return smartport dispatch address
|
||
|
*/
|
||
|
uint16_t sp_dispatch_address(uint8_t slot)
|
||
|
{
|
||
|
uint16_t a = (slot * 0x100) + 0xC000;
|
||
|
uint8_t j = PEEK(a+0xFF);
|
||
|
|
||
|
return a + j + 3;
|
||
|
}
|
||
|
|
||
|
void sp_init(void)
|
||
|
{
|
||
|
uint8_t slot, f;
|
||
|
slot = sp_find_slot();
|
||
|
if (slot)
|
||
|
sp_dispatch = sp_dispatch_address(slot);
|
||
|
else
|
||
|
cprintf("No SmartPort Firmware Found!");
|
||
|
//sp_list_devs();
|
||
|
f = sp_find_fuji();
|
||
|
if (f < 1)
|
||
|
cprintf("FujiNet Not Found!");
|
||
|
}
|
||
|
|
||
|
#endif /* BUILD_APPLE2 */
|