Begin implementing driver model.

This commit is contained in:
Kyle J Cardoza 2024-07-07 23:08:08 -04:00
parent 3e888ffa65
commit 57ce078167
27 changed files with 614 additions and 23436 deletions

View File

@ -6,9 +6,9 @@ TARGET := sentinel-65x-512K
all: build/$(TARGET).bin
include config/boot.mk
include config/bios.mk
include config/kernel.mk
build/$(TARGET).bin: build/boot.bin build/bios.bin
build/$(TARGET).bin: build/boot.bin build/kernel.bin
#Create an empty .bin file.
@dd if=/dev/zero of=$@ bs=1024 count=512
@ -16,7 +16,7 @@ build/$(TARGET).bin: build/boot.bin build/bios.bin
@dd if=build/boot.bin of=$@ bs=1024 seek=32 conv=notrunc
# Add the bios module at offset 0x008300
@dd if=build/bios.bin of=$@ bs=1 seek=33536 conv=notrunc
@dd if=build/kernel.bin of=$@ bs=1 seek=33536 conv=notrunc
.PHONY: clean
clean:

View File

@ -1,12 +0,0 @@
BIOS_ASM_SRC := $(wildcard src/bios/*.s)
BIOS_C_SRC := $(wildcard src/bios/*.c)
BIOS_OBJ := $(BIOS_ASM_SRC:.s=.o)
BIOS_OBJ += $(BIOS_C_SRC:.c=.o)
BIOS_LDFLAGS := --list-file build/bios.lst
build/bios.bin: $(BIOS_OBJ)
echo "Linking $@..."
$(LD) -o $@ config/bios.scm $(LDFLAGS) $(BIOS_LDFLAGS) $^
mv build/bios.raw $@

20
config/kernel.mk Normal file
View File

@ -0,0 +1,20 @@
KERNEL_ASM_SRC := $(wildcard src/kernel/*.s) \
$(wildcard src/kernel/*/*.s) \
$(wildcard src/kernel/*/*/*.s) \
$(wildcard src/kernel/*/*/*/*.s) \
$(wildcard src/kernel/*/*/*/*.s)
KERNEL_C_SRC := $(wildcard src/kernel/*.c) \
$(wildcard src/kernel/*/*.c) \
$(wildcard src/kernel/*/*/*.c) \
$(wildcard src/kernel/*/*/*/*.c) \
$(wildcard src/kernel/*/*/*/*/*.c)
KERNEL_OBJ := $(KERNEL_ASM_SRC:.s=.o)
KERNEL_OBJ += $(KERNEL_C_SRC:.c=.o)
KERNEL_LDFLAGS := --list-file build/kernel.lst
build/kernel.bin: $(KERNEL_OBJ)
echo "Linking $@..."
$(LD) -o $@ config/kernel.scm $(LDFLAGS) $(KERNEL_LDFLAGS) $^
mv build/kernel.raw $@

View File

@ -5,17 +5,20 @@
(section zhuge)
(section znear)
(section zdata)
(section huge)
(section heap)
)
(memory ROM
(address (#xC08300 . #xC0FFFF))
(section code)
(section (code #xC08300))
(section farcode)
(section cdata)
(section switch)
(section near)
(section data)
(section chuge)
(section ihuge)
(section (irq_trampolines #xC0F000))
(section (irq_vectors #xC0FF80))
)

View File

@ -1,10 +1,12 @@
// SPDX-License-Identifier: MIT
//
// boot/w65c816s.h
// Assembly defines for the 65C816 architecture
// Defines for the 65C816 architecture
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#ifdef __CALYPSI_ASSEMBLER__
#define native_mode \
clc \
xce
@ -32,3 +34,5 @@
plx \
pla \
plp
#endif

113
include/kernel/device.h Normal file
View File

@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
//
// kernel/device.h
// Driver declarations.
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#pragma once
#ifdef __CALYPSI_CC__
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
// This symbol determines the maximum number of device drivers which
// can be in memory.
#ifndef DEVICE_MAX
#define DEVICE_MAX 32
#endif
// This symbol determines the maximum number of device map entries which
// ca be in memory.
#ifndef DEVICE_MAP_MAX
#define DEVICE_MAP_MAX 32
#endif
// Forward declaration.
struct file;
// A device, in this context, is a code module which exposes a defined set
// of functions for interacting with files and file-like data. It is not specific
// as to the nature of the underlying data storage. It is equally valid for a
// device to use a block of RAM or a serial device as it is a hard drive
// or SD card.
//
// None of these functions are required to actually do anyting if it is not
// sensible for the kind of device being used; for example, it is not
// sensible for an inherently read-only device to support moving or
// renaming files.
typedef struct {
// Initialize the device.
int (*init)(void);
// Opens a file, given a pathname.
int (*open)(struct file *file);
// Closes an open file, given a unique ID.
int (*close)(struct file *file);
// Seeks within an open file, given a unique ID and a length.
int (*seek)(struct file *file, long length);
// Reads data from the specified file.
int (*read)(struct file *file, void *dest, size_t length);
// Writes data to the specified file.
int (*write)(struct file *file, void *src, size_t length);
// Perform driver-specific operations.
int (*ioctl)(struct file *file,
unsigned short operation,
void *arg);
// Creates the specified file given a pathname.
int (*create)(struct file *file);
// Copies the specified file using the specified names.
int (*copy)(struct file *src,
struct file *dest);
// Moves the specified file using the specified names.
int (*move)(struct file *src,
struct file *dest);
// Gets the size of the file.
int (*get_file_size)(struct file *file, size_t *size);
// Fills out the metadata in the specified file from the pathname
// in the provided file.
int (*init_file)(struct file *file);
} Device;
// The device map is a table that maps device names, such as SD0: or
// TTY2: to the device driver that manages the device.
struct device_map {
char *name;
unsigned short major_number;
unsigned short minor_number;
};
// The global table of device drivers.
extern Device *device[DEVICE_MAX];
// The global map of device names to device modules.
extern struct device_map *device_map[DEVICE_MAP_MAX];
// Initialize all the device drivers. This is called once, at boot.
// It protects itself against being called again without a reset.
void device_init_all(void);
// Binds a device name to a device.
int device_bind_name(char *name,
unsigned short major_number,
unsigned short minor_number);
// Unbinds a bound device name.
int device_unbind_name(char *name);
// Get a bound device by its name.
int device_get_by_name(char *name, Device **device);
#endif

View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
//
// kernel/device/null.h
// NULL driver declaration.
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#pragma once
#include "kernel/device.h"
extern Device NullDevice;

75
include/kernel/file.h Normal file
View File

@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT
//
// kernel/file.h
// File related declarations
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "kernel/device.h"
enum file_type {
FILE_TYPE_NORMAL,
FILE_TYPE_DIRECTORY,
FILE_TYPE_DEVICE
};
struct file {
// The full path of the file, including its volume and basename.
char *pathname;
// The basename of the file. This usually points to
// the begining of the basename of the file in the
// pathname string.
char *basename;
// The type of the file.
enum file_type type;
bool open;
// Generic driver-specific data pointer
void *userdata;
// The major number identifies the device driver responsible for
// the file.
uint8_t major_number;
// The minor number identifies the device, among those the driver
// controls, which this file represents or is associated with.
uint8_t minor_number;
};
// Using the pathname in the provided FCB, identify the device which manages
// the file and have that device populate the FCB.
int file_init(char *pathname, struct file *file);
int file_open(struct file *file);
// Closes an open file, given a unique ID.
int file_close(struct file *file);
// Seeks within an open file, given a unique ID and a length.
int file_seek(struct file *file, int32_t length);
// Reads data from the specified file.
int file_read(struct file *file, void *dest, size_t length);
// Writes data to the specified file.
int file_write(struct file *file, void *src, size_t length);
// Creates the specified file given a pathname.
int file_create(struct file *file);
// Copies the specified file using the specified names.
int file_copy(struct file *src, struct file *dest);
// Moves the specified file using the specified names.
int file_move(struct file *src, struct file *dest);
// Gets the size of the file.
int file_get_file_size(struct file *file, size_t *size);

View File

@ -5,6 +5,8 @@
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#pragma once
#define CPU_SPEED_HZ 8000000
#define UART3_BAUD_RATE 9600
#define UART3_TIMER_VALUE (CPU_SPEED_HZ / (16 * UART3_BAUD_RATE) - 1)

View File

@ -1,10 +1,15 @@
// SPDX-License-Identifier: MIT
//
// boot/vera.h
// Assembly language defines for the VERA chip
// Defines for the VERA chip
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#ifdef __CALYPSI_CC__
#include <stddef.h>
#include <stdint.h>
#endif
#define AUTO_NONE 0x000000
#define AUTO_INC_1 0x100000
#define AUTO_INC_2 0x200000
@ -122,3 +127,32 @@
#define VERA_PSG_BASE 0x01F9C0
#define VERA_PALETTE_BASE 0x01FA00
#define VERA_SPRITE_ATTR_BASE 0x01FC00
// The assembler can't handle this stuff.
#ifdef __CALYPSI_CC__
void vera_set_address_0(uint32_t addr);
void vera_set_address_1(uint32_t addr);
uint8_t vera_read_data_reg_0(void);
uint8_t vera_read_data_reg_1(void);
uint16_t vera_read_data_reg(void);
void vera_write_data_reg_0(uint8_t new_value);
void vera_write_data_reg_1(uint8_t new_value);
void vera_write_data_reg(uint16_t new_value);
void vera_reset(void);
void vera_mem_read(void *dest, uint32_t src, size_t length);
void vera_mem_write(uint32_t dest, void *src, size_t length);
void vera_mem_set(uint32_t dest, uint8_t value, size_t length);
#endif

View File

@ -1,11 +1,10 @@
// SPDX-License-Identifier: MIT
//
// boot/w65c265s.h
// Assembly defines for the W65C265S chip
// Defines for the W65C265S chip
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#define PD0 0x00DF00
#define PD1 0x00DF01
#define PD2 0x00DF02
@ -87,6 +86,8 @@
#define PIR6 0x00DF7E
#define PIR7 0x00DF7F
#ifdef __CALYPSI_ASSEMBLER__
; Enable the 512 bytes of on-CPU SRAM from 0x000000-0001FF
w65c265s_sram_on .macro
lda #0b00000100
@ -126,4 +127,6 @@ fclk_stop .macro
fclk_select .macro
lda #0b11111010
tsb SSCR
.endm
.endm
#endif

BIN
src/bdos/.DS_Store vendored

Binary file not shown.

View File

@ -1,35 +0,0 @@
FatFs License
FatFs has being developped as a personal project of the author, ChaN. It is
free from the code anyone else wrote at current release. Following code block
shows a copy of the FatFs license document that heading the source files.
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem Module Rx.xx /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 20xx, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/----------------------------------------------------------------------------*/
Therefore FatFs license is one of the BSD-style licenses, but there is a
significant feature. FatFs is mainly intended for embedded systems. In order to
extend the usability for commercial products, the redistributions of FatFs in
binary form, such as embedded code, binary library and any forms without source
code, do not need to include about FatFs in the documentations. This is
equivalent to the 1-clause BSD license. Of course FatFs is compatible with
the most of open source software licenses include GNU GPL. When you
redistribute the FatFs source code with changes or create a fork, the license
can also be changed to GNU GPL, BSD-style license or any open source software
license that not conflict with FatFs license.

View File

@ -1,470 +0,0 @@
/*------------------------------------------------------------------------/
/ Foolproof MMCv3/SDv1/SDv2 (in SPI mode) control module
/-------------------------------------------------------------------------/
/
/ Copyright (C) 2019, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-------------------------------------------------------------------------/
Features and Limitations:
* No Media Change Detection
Application program needs to perform a f_mount() after media change.
/-------------------------------------------------------------------------*/
#include "kernel/drivers/fatfs/ff.h" /* Obtains integer types for FatFs */
#include "kernel/drivers/fatfs/diskio.h" /* Common include file for FatFs and disk I/O layer */
/*-------------------------------------------------------------------------*/
/* Platform dependent macros and functions needed to be modified */
/*-------------------------------------------------------------------------*/
/*---------------------------------------------------------*/
/* User Provided RTC Function for FatFs module */
/*---------------------------------------------------------*/
/* This is a real time clock service to be called from */
/* FatFs module. Any valid time must be returned even if */
/* the system does not support an RTC. */
/* This function is not required in read-only cfg. */
// FIXME: Make this use the system RTC.
DWORD get_fattime (void)
{
return 0;
}
// FIXME: Make this delay using a system timer.
static void
dly_us (int n)
{
(void) n;
}
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
/* MMC/SD command (SPI mode) */
#define CMD0 (0) /* GO_IDLE_STATE */
#define CMD1 (1) /* SEND_OP_COND */
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
#define CMD8 (8) /* SEND_IF_COND */
#define CMD9 (9) /* SEND_CSD */
#define CMD10 (10) /* SEND_CID */
#define CMD12 (12) /* STOP_TRANSMISSION */
#define CMD13 (13) /* SEND_STATUS */
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
#define CMD16 (16) /* SET_BLOCKLEN */
#define CMD17 (17) /* READ_SINGLE_BLOCK */
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (23) /* SET_BLOCK_COUNT */
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (24) /* WRITE_BLOCK */
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
#define CMD32 (32) /* ERASE_ER_BLK_START */
#define CMD33 (33) /* ERASE_ER_BLK_END */
#define CMD38 (38) /* ERASE */
#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
static
DSTATUS Stat = STA_NOINIT; /* Disk status */
static
BYTE CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */
/*-----------------------------------------------------------------------*/
/* Transmit bytes to the card */
/*-----------------------------------------------------------------------*/
// FIXME: Make this use VERA.
static
void xmit_mmc (const BYTE* buff, UINT count)
{
(void) buff;
(void) count;
}
/*-----------------------------------------------------------------------*/
/* Receive bytes from the card */
/*-----------------------------------------------------------------------*/
// FIXME: Make this use VERA.
static
void rcvr_mmc (BYTE *buff, UINT count)
{
(void) buff;
(void) count;
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready */
/*-----------------------------------------------------------------------*/
static
int wait_ready (void) /* 1:OK, 0:Timeout */
{
BYTE d;
UINT tmr;
for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */
rcvr_mmc(&d, 1);
if (d == 0xFF) break;
dly_us(100);
}
return tmr ? 1 : 0;
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus */
/*-----------------------------------------------------------------------*/
// FIXME: Make this use VERA.
static
void deselect (void)
{
}
/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready */
/*-----------------------------------------------------------------------*/
// FIXME: Make this use VERA.
static
int select (void) /* 1:OK, 0:Timeout */
{
return 0; /* Failed */
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from the card */
/*-----------------------------------------------------------------------*/
static
int rcvr_datablock ( /* 1:OK, 0:Failed */
BYTE *buff, /* Data buffer to store received data */
UINT btr /* Byte count */
)
{
BYTE d[2];
UINT tmr;
for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */
rcvr_mmc(d, 1);
if (d[0] != 0xFF) break;
dly_us(100);
}
if (d[0] != 0xFE) return 0; /* If not valid data token, return with error */
rcvr_mmc(buff, btr); /* Receive the data block into buffer */
rcvr_mmc(d, 2); /* Discard CRC */
return 1; /* Return with success */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to the card */
/*-----------------------------------------------------------------------*/
static
int xmit_datablock ( /* 1:OK, 0:Failed */
const BYTE *buff, /* 512 byte data block to be transmitted */
BYTE token /* Data/Stop token */
)
{
BYTE d[2];
if (!wait_ready()) return 0;
d[0] = token;
xmit_mmc(d, 1); /* Xmit a token */
if (token != 0xFD) { /* Is it data token? */
xmit_mmc(buff, 512); /* Xmit the 512 byte data block to MMC */
rcvr_mmc(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */
rcvr_mmc(d, 1); /* Receive data response */
if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */
return 0;
}
return 1;
}
/*-----------------------------------------------------------------------*/
/* Send a command packet to the card */
/*-----------------------------------------------------------------------*/
static
BYTE send_cmd ( /* Returns command response (bit7==1:Send failed)*/
BYTE cmd, /* Command byte */
DWORD arg /* Argument */
)
{
BYTE n, d, buf[6];
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
n = send_cmd(CMD55, 0);
if (n > 1) return n;
}
/* Select the card and wait for ready except to stop multiple block read */
if (cmd != CMD12) {
deselect();
if (!select()) return 0xFF;
}
/* Send a command packet */
buf[0] = 0x40 | cmd; /* Start + Command index */
buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */
buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */
buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */
buf[4] = (BYTE)arg; /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* (valid CRC for CMD0(0)) */
if (cmd == CMD8) n = 0x87; /* (valid CRC for CMD8(0x1AA)) */
buf[5] = n;
xmit_mmc(buf, 6);
/* Receive command response */
if (cmd == CMD12) rcvr_mmc(&d, 1); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
rcvr_mmc(&d, 1);
while ((d & 0x80) && --n);
return d; /* Return with the response value */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv /* Drive number (always 0) */
)
{
if (drv) return STA_NOINIT;
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0) */
)
{
BYTE n, ty, cmd, buf[4];
UINT tmr;
DSTATUS s;
if (drv) return RES_NOTRDY;
dly_us(10000); /* 10ms */
for (n = 10; n; n--) rcvr_mmc(buf, 1); /* Apply 80 dummy clocks and the card gets ready to receive command */
ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
rcvr_mmc(buf, 4); /* Get trailing return value of R7 resp */
if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (send_cmd(ACMD41, 1UL << 30) == 0) break;
dly_us(1000);
}
if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
rcvr_mmc(buf, 4);
ty = (buf[0] & 0x40) ? CT_SDC2 | CT_BLOCK : CT_SDC2; /* SDv2+ */
}
}
} else { /* SDv1 or MMCv3 */
if (send_cmd(ACMD41, 0) <= 1) {
ty = CT_SDC2; cmd = ACMD41; /* SDv1 */
} else {
ty = CT_MMC3; cmd = CMD1; /* MMCv3 */
}
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */
if (send_cmd(cmd, 0) == 0) break;
dly_us(1000);
}
if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
}
CardType = ty;
s = ty ? 0 : STA_NOINIT;
Stat = s;
deselect();
return s;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
LBA_t sector, /* Start sector number (LBA) */
UINT count /* Sector count (1..128) */
)
{
BYTE cmd;
DWORD sect = (DWORD)sector;
if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;
if (!(CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */
cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
if (send_cmd(cmd, sect) == 0) {
do {
if (!rcvr_datablock(buff, 512)) break;
buff += 512;
} while (--count);
if (cmd == CMD18) send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
}
deselect();
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0) */
const BYTE *buff, /* Pointer to the data to be written */
LBA_t sector, /* Start sector number (LBA) */
UINT count /* Sector count (1..128) */
)
{
DWORD sect = (DWORD)sector;
if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;
//if (!(CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */
if (count == 1) { /* Single block write */
if ((send_cmd(CMD24, sect) == 0) /* WRITE_BLOCK */
&& xmit_datablock(buff, 0xFE))
count = 0;
}
else { /* Multiple block write */
if (CardType & CT_SDC) send_cmd(ACMD23, count);
if (send_cmd(CMD25, sect) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!xmit_datablock(buff, 0xFC)) break;
buff += 512;
} while (--count);
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
count = 1;
}
}
deselect();
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
BYTE n, csd[16];
DWORD cs;
if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY; /* Check if card is in the socket */
res = RES_ERROR;
switch (ctrl) {
case CTRL_SYNC : /* Make sure that no pending write process */
if (select()) res = RES_OK;
break;
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
*(LBA_t*)buff = cs << 10;
} else { /* SDC ver 1.XX or MMC */
n = (BYTE)((csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2);
cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(LBA_t*)buff = cs << (n - 9);
}
res = RES_OK;
}
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
*(DWORD*)buff = 128;
res = RES_OK;
break;
default:
res = RES_PARERR;
}
deselect();
return res;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,207 +0,0 @@
/*------------------------------------------------------------------------*/
/* A Sample Code of User Provided OS Dependent Functions for FatFs */
/*------------------------------------------------------------------------*/
#include "kernel/drivers/fatfs/ff.h"
#if FF_USE_LFN == 3 /* Use dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate/Free a Memory Block */
/*------------------------------------------------------------------------*/
#include "stdlib.h" /* with POSIX API */
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
return malloc((size_t)msize); /* Allocate a new memory block */
}
void ff_memfree (
void* mblock /* Pointer to the memory block to free (no effect if null) */
)
{
free(mblock); /* Free the memory block */
}
#endif
#if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/
/* Definitions of Mutex */
/*------------------------------------------------------------------------*/
#define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */
#if OS_TYPE == 0 /* Win32 */
#include <windows.h>
static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
#elif OS_TYPE == 1 /* uITRON */
#include "itron.h"
#include "kernel.h"
static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
#elif OS_TYPE == 2 /* uc/OS-II */
#include "includes.h"
static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */
#elif OS_TYPE == 3 /* FreeRTOS */
#include "FreeRTOS.h"
#include "semphr.h"
static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
#elif OS_TYPE == 4 /* CMSIS-RTOS */
#include "cmsis_os.h"
static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
#endif
/*------------------------------------------------------------------------*/
/* Create a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to create a new mutex
/ or semaphore for the volume. When a 0 is returned, the f_mount function
/ fails with FR_INT_ERR.
*/
int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
Mutex[vol] = CreateMutex(NULL, FALSE, NULL);
return (int)(Mutex[vol] != INVALID_HANDLE_VALUE);
#elif OS_TYPE == 1 /* uITRON */
T_CMTX cmtx = {TA_TPRI,1};
Mutex[vol] = acre_mtx(&cmtx);
return (int)(Mutex[vol] > 0);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
Mutex[vol] = OSMutexCreate(0, &err);
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
Mutex[vol] = xSemaphoreCreateMutex();
return (int)(Mutex[vol] != NULL);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDef(cmsis_os_mutex);
Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex));
return (int)(Mutex[vol] != NULL);
#endif
}
/*------------------------------------------------------------------------*/
/* Delete a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to delete a mutex or
/ semaphore of the volume created with ff_mutex_create function.
*/
void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
CloseHandle(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
del_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err);
#elif OS_TYPE == 3 /* FreeRTOS */
vSemaphoreDelete(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDelete(Mutex[vol]);
#endif
}
/*------------------------------------------------------------------------*/
/* Request a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on enter file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0);
#elif OS_TYPE == 1 /* uITRON */
return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err));
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK);
#endif
}
/*------------------------------------------------------------------------*/
/* Release a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leave file functions to unlock the volume.
*/
void ff_mutex_give (
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
ReleaseMutex(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
unl_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OSMutexPost(Mutex[vol]);
#elif OS_TYPE == 3 /* FreeRTOS */
xSemaphoreGive(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexRelease(Mutex[vol]);
#endif
}
#endif /* FF_FS_REENTRANT */

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
//*****************************************************************************
// 65X-DOS
//
// src/bdos/main.c
//*****************************************************************************
#include "config.h"
void
main(void)
{
for (;;) {}
}

View File

@ -50,4 +50,4 @@ delay_y
sta PCS7
// And we are booted enough to jump to high ROM.
jmp 0xC00000
jmp long:0xC08300

122
src/kernel/device.c Normal file
View File

@ -0,0 +1,122 @@
// SPDX-License-Identifier: MIT
//
// kernel/device.c
// Device drivers.
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "kernel/device.h"
#include "kernel/file.h"
static bool device_init_all_run = false;
Device *device[DEVICE_MAX] = {
NULL
};
struct device_map *device_map[DEVICE_MAP_MAX] = {0};
static short get_lowest_free_device(void);
void device_init_all(void)
{
if (device_init_all_run == true) {
return;
}
for (int i = 0; i < DEVICE_MAX; i += 1) {
if (device[i] != NULL) {
if (device[i]->init != NULL) {
device[i]->init();
}
}
}
device_init_all_run = true;
}
int device_bind_name(char *name,
unsigned short major_number,
unsigned short minor_number)
{
if (name == NULL) {
return -1;
}
// It is not permissible to have the same name attached to two
// devices.
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
if (strcmp(device_map[i]->name, name) == 0) {
return -1;
}
}
short device_index = get_lowest_free_device();
if (device_index == -1) {
return -1;
}
char *device_name = strdup(name);
if (name == NULL) {
return -1;
}
device_map[device_index] = calloc(1, sizeof(struct device_map));
if (device_map[device_index] == NULL) {
free(device_name);
return -1;
} else {
device_map[device_index]->major_number = major_number;
device_map[device_index]->minor_number = minor_number;
device_map[device_index]->name = device_name;
return 0;
}
}
int device_unbind_name(char *name)
{
if (name == NULL) {
return -1;
}
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
if (strcmp(device_map[i]->name, name) == 0) {
free(device_map[i]->name);
free(device_map[i]);
device_map[i] = NULL;
return 0;
}
}
return -1;
}
int device_get_by_name(char *name, Device **device)
{
if (name == NULL || device == NULL) {
return -1;
}
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
if (strcmp(device_map[i]->name, name) == 0) {
unsigned short major_number = device_map[i]->major_number;
*device = device[major_number];
return 0;
}
}
return -1;
}
static short get_lowest_free_device(void)
{
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
if (device_map[i] == NULL) {
return i;
}
}
return -1;
}

126
src/kernel/device/null.c Normal file
View File

@ -0,0 +1,126 @@
// SPDX-License-Identifier: MIT
//
// kernel/device/null.c
// NULL device implementation.
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#include <string.h>
#include "kernel/device/null.h"
#include "kernel/device.h"
#include "kernel/file.h"
static int null_init(void);
static int null_open(struct file *file);
static int null_close(struct file *file);
static int null_read(struct file *file, void *dest, size_t length);
static int null_write(struct file *file, void *src, size_t length);
static int null_get_file_size(struct file *file, size_t *size);
static int null_init_file(struct file *file);
Device NullDevice = {
.init = null_init,
.open = null_open,
.close = null_close,
.read = null_read,
.write = null_write,
.get_file_size = null_get_file_size,
.init_file = null_init_file
};
static int null_init(void)
{
device_bind_name("zero", 0, 0);
device_bind_name("null", 0, 1);
return 0;
}
static int null_open(struct file *file)
{
switch (file->minor_number) {
case 0 ... 1:
file->open = true;
return 0;
default:
return -1;
}
}
static int null_close(struct file *file)
{
switch (file->minor_number) {
case 0 ... 1:
file->open = false;
return 0;
default:
return -1;
}
}
static int null_read(struct file *file,
void *dest,
size_t length)
{
if (file->open == false) {
return -1;
}
switch (file->minor_number) {
case 0:
memset(dest, 0x00, length);
return length;
default:
return -1;
}
}
static int null_write(struct file *file,
void *src,
size_t length)
{
if (file->open == false) {
return -1;
}
(void) src;
if (file->minor_number != 1) {
return -1;
} else {
return length;
}
}
static int null_get_file_size(struct file *file,
size_t *size)
{
switch (file->minor_number) {
case 0 ... 1:
*size = 0;
return 0;
default:
return -1;
}
}
static int null_init_file(struct file *file)
{
if (file->major_number != 0) {
return -1;
}
switch (file->minor_number) {
case 0 ... 1:
file->open = false;
file->type = FILE_TYPE_DEVICE;
return 0;
default:
return -1;
}
}

57
src/kernel/file.c Normal file
View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: MIT
//
// kernel/file.c
// File definitions.
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#include <stdlib.h>
#include <string.h>
#include "kernel/file.h"
#include "kernel/device.h"
// Using the pathname string, identify the major/minor device for
// the file, and have that device initialize the file control
// block.
int file_init(char *pathname, struct file *file)
{
// First thing, we need to identify the device. The pathname
// is to be fully-qualified; this means it must have the
// device name, followed by a colon, followed by an optional
// file path. If the file path part is empty, then the file
// refers to the device itself. We perform the identification
// by first copying the pathname, then tokenizing the copy on
// the ":" character. The first token must be a string which
// matches a registered device in the device map.
// Then we populate the located major and minor numbers and copy
// the pathname into the FCB, and pass it along to the device
// driver for more initialization.
char *path = strdup(pathname);
if (path == NULL) {
return -1;
}
char *dev = strtok(path, ":");
for (unsigned short i = 0; i < DEVICE_MAP_MAX; i += 1) {
if (strcmp(dev, device_map[i]->name) == 0) {
file->pathname = strdup(pathname);
free(path);
if (file->pathname == NULL) {
return -1;
}
file->major_number = device_map[i]->major_number;
file->minor_number = device_map[i]->minor_number;
return device[file->major_number]->init_file(file);
}
}
free(path);
return -1;
}

View File

@ -12,15 +12,29 @@
// DP[6] for the Y register.
extern uint16_t Dp[4];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
void cop_handler(uint16_t arg_c, uint16_t arg_x, uint16_t arg_y) {
switch (arg_c & 0x00FF) {
case 0:
//soft_reset();
break;
default:
//cop_error_invalid_call();
break;
}
}
void irq_handler(void) {
return;
}
void brk_irq_handler(void) {
void brk_handler(void) {
return;
}
void abort_irq_handler(void) {
void abort_handler(void) {
return;
}
@ -124,10 +138,4 @@ void uart_3_tx_irq_handler(void) {
return;
}
void cop_handler(uint16_t arg_c, uint16_t arg_x, uint16_t arg_y) {
(void) arg_c;
(void) arg_x;
(void) arg_y;
return;
}
#pragma clang diagnostic pop

View File

@ -16,6 +16,7 @@
.extern _Dp
.extern irq_handler
.extern cop_handler
; This section gets copied to 0x00F000
.section irq_trampolines
@ -251,11 +252,17 @@ uart_3_tx_irq:
cop_irq:
phb
phd
rep #0b00110000
pha
phx
phy
jump interrupt_return
rep #0b00110000
stx _Dp+4
sty _Dp+6
call cop_handler
rep #0b00110000
lda _Dp+0
ldx _Dp+4
ldy _Dp+6
pld
plb
rti
brk_irq:
phb

View File

@ -5,6 +5,10 @@
//
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
#include "kernel/device.h"
void main(void) {
device_init_all();
for (;;) {}
}