Close
0%
0%

OSI SD Card Operating System (OSISDOS)

Ohio Scientific / UK101 SD Card based Operating System under Multicomp FPGA Computer

Similar projects worth following
Make an SD card Operating System for the Ohio Scientific / UK101 which runs with the Multicomp FPGA Computer

Grant Searle's FPGA computer project, Multicomp, has support for the Ohio Scientific / UK 101 from the late 1970's. There's also hardware support in the Multicomp project for SD Cards but so far there's no software support for the SD Card with the OSI / UK101 design.

The goal of this project is to use the existing hardware base to create an SD card Operating System. The desired features are:

  • Replace "D" (Disk) selection at boot in CEGMON monitor
  • Boot to file selector/loader
  • Support for loading BASIC or Machine Language programs
  • SDHC supports FAT32 file system
    • Programs can be loaded from a PC to the SD Card
  • Support for SDHC cards up to 32 GB
    • Cards larger than 64 GB can be formatted as SDHC (not exFAT)

  • DOS/65

    land-boards.com08/30/2020 at 17:36 0 comments

    It looks as if someone has done a lot of the heavy lifting towards making an operating system for the 6502. The project is DOS/65 by Richard A. Leary.

    This could save a lot of work. Richard chose to have a lot of compatibility with CP/M and I've got a lot of time already invested with the Multicomp CP/M systems.

    Not sure how tough it will be to port the DOS/65 system but it has to be a lot less than writing an OS from scratch.

  • OSISDOS Command Line

    land-boards.com08/08/2020 at 17:10 0 comments

    Now that the input and output work, it's time to work on the command line. At a high level, a notional set of commands could be:

    • mnt - mount the SD card, load/parse the boot record
    • dir - fetch the directory from the SD card and display to the screen, starts in root folder
    • cd - change directory
    • ld - load a file from the SD card

  • Screen Handler Code

    land-boards.com08/08/2020 at 11:38 0 comments

    Now that the low level SD card code is working well it's time to give some attention to the command handler. Making this work will require screen/keyboard I/O and cc65 does provide support for I/O. 

    This is where things start to get a bit ugly. To start with, there is no stdio.h support for the C1P in cc65

    conio on the C1P

    There is a conio.h file in cc65 which supports command style I/O from the console but it has serious limitations. For instance, from this page:

    ... conio doesn't scroll the screen when moving below the last line. 
    In fact, allowing that to happen might spell disaster on several
    machines because, for performance reasons, there are no checks.

    The example code from the tutorial works with some changes but it is flakey. I removed the text section from the example but will probably need to add it back in later when moving this code to the ROM.

    /* hello.c example    */
    /* conio.h docs - Not sure how well it matches    */
    /*     https://digitalmars.com/rtl/conio.html     */
    
    #include <conio.h>    /* Console I/O    */
    #include <stdlib.h>
    
    int main (void)
    {
        clrscr ();
        cprintf ("\r\nPress <RETURN>.");
        cgetc ();
        return EXIT_SUCCESS;
    }
    

    The result is that the "Press <RETURN>" message is printed to the right on the screen. It does wait for a key to be pressed so it's basically working. 

    The example above is built using this command line.

    "..\..\..\PC Tools\srecord\srec_cat.exe" hello.o -bin -of 0x300 -o hello.c1p -os -esa=0x300

    The function three functions do work (at least intermittently in the case of the cprintf function):

    • clrscr()  - Clears the screen
    • cprintf ("str") - Prints string to the screen
    • cgetc() - Waits for a character.

    The screen size on the UK101 Multicomp build is currently 48 columns x 16 rows. The default C1P screen is formatted for a different size:

    By default the conio library uses a 24 columns by 24 lines 
    screen layout for the Challenger 1P.
    
    There is a module screen-c1p-24x24.o in the OSI-specific 
    cc65 runtime library that contains all conio functions that 
    depend on the screen layout. 
    No further configuration is needed for using the default screen 
    layout of the Challenger 1P.

    There is support for other screen layouts but they are limited to:

    For other screen layouts additional versions of the screen module 
    are available.
    The linker finds these modules without further configuration if 
    they are specified on the compiler or linker command line. 
    The extra module then overrides the default module.
    
    Sample cl65 command line to override the default screen module with 
    the module osic1p-screen-s3-32x28.o:
    
    cl65 -o hello -t osic1p osic1p-screen-s3-32x28.o hello.c
    
    Currently the following extra screen configuration modules are 
    implemented:
    
    osic1p-screen-s3-32x28.o: 32 columns by 28 lines mode for 
    Briel Superboard ///

    It looks like all that needs to be done is to create a version of the osic1p-screen-s3-32x28.o file for our screen and have it override the default resolution.

    Here is the source code for the 24x24 display. with a few comments added:

    ;
    ; Implementation of screen-layout related functions for Challenger 1P
    ;
    
            .include        "osiscreen.inc"
    
    C1P_SCR_BASE    := $D000        ; Base of C1P video RAM
    C1P_VRAM_SIZE   = $0400         ; Size of C1P video RAM (1 kB)
    C1P_SCR_WIDTH   = $18           ; Screen width (24)
    C1P_SCR_HEIGHT  = $18           ; Screen height (24)
    C1P_SCR_FIRSTCHAR = $85         ; Offset of cursor position (0, 0) from base
                                    ; of video RAM
    C1P_SCROLL_DIST = $20           ; Memory distance for scrolling by one line (32 chars/line)
    
    osi_screen_funcs C1P_SCR_BASE, C1P_VRAM_SIZE, C1P_SCR_FIRSTCHAR, \
                            C1P_SCR_WIDTH, C1P_SCR_HEIGHT, C1P_SCROLL_DIST

    The windows distribution of cc65 does not include the source tree for the C1P libraries but it is on the GitHub repository located here. Changing the screen requires making a new screen file with:

    ;
    ; Implementation of 48x16 screen-layout related functions for Challenger 1P
    ;
    
            .include        "osiscreen.inc"
    
    C1P_SCR_BASE :=...
    Read more »

  • From the Directory to the File

    land-boards.com08/05/2020 at 22:39 0 comments

    In the previous log I got the directory to read into the RAMDISK space. This step will go from the directory to a file. This page gives a nice synopsis.

    From my previous log, the directory on my SD card looks like:

    Directory entries are in 32-byte blocks, for instance the RAMTEST.BAS entry has:

    The Microsoft Extensible Firmware Initiative FAT32 File System Specification provides additional information in tabular form

    NameOffset (byte)Size (bytes)Description
    DIR_Name011Short name.
    <RAMTEST BAS>
    DIR_Attr111File attributes:
    ATTR_READ_ONLY 0x01
    ATTR_HIDDEN 0x02
    ATTR_SYSTEM 0x04
    ATTR_VOLUME_ID 0x08
    ATTR_DIRECTORY 0x10
    ATTR_ARCHIVE 0x20
    ATTR_LONG_NAME 
    ATTR_READ_ONLY | 
    ATTR_HIDDEN | 
    ATTR_SYSTEM | 
    ATTR_VOLUME_ID 
    The upper two bits of the attribute byte are reserved
    and  should always be set to 0 when a file is created
    and  never modified or looked at after that.
    <0x20>
    DIR_NTRes121Reserved for use by Windows NT. 
    Set value to 0 when a file is created and never modify
    or look at it after that.
    <0x00>
    DIR_CrtTimeTenth131Millisecond stamp at file creation time. 
    This field actually contains a count of tenths of a second. 
    The granularity of the seconds part of DIR_CrtTime is
    2 seconds  so this field is a count of tenths of
    a second and its  valid value range is 0-199 inclusive.
    <0xA7>
    DIR_FstClusHI202High word of this entry’s first cluster number 
    (always 0 for a FAT12 or FAT16 volume).
    <0x0000>
    DIR_WrtTime222Time of last write. Note that file creation  is considered a write. <0x00DD>
    DIR_WrtDate242Date of last write. Note that file creation is considered a write. <0xF9A4>
    DIR_FstClusLO262Low word of this entry’s first cluster number.
    <0x0007> = 7 dec
    DIR_FileSize28432-bit DWORD holding this file’s size in bytes.
    <0x0000019C> = 412 dec

    So, the cluster number for RAMTEST.BAS is 56. From the boot record, there are 8 sectors per cluster. 

    13      BPB_SecPerClus        Number of sectors per cluster (1)        Must be one of 1, 2, 4, 8, 16, 32, 64, 128.        A cluster should have at most 32768 bytes.         In rare cases 65536 is OK.        <0x08> = 8 sectors per clusters

    That means the file starts at cluster 7 * 8 = 56. This should be relative to the FirstDataSector calculated above to be 32,768. So the first sector number for RAMTEST.BAS should be at 32,768+56=32,824. However, the file is actually 16 sectors earlier at sector 32,808. Must be an offset of 2 clusters?

    Here's the answer:

    Looking at the hex dump

    • DISKREAD.BAS is at sector 32,800 (32,768 + 32).
    • RAMTEST.BAS is at sector 32,808 (32,768+40). 
    • BANKTEST.BAS is at sector 32,816 (32,768+56).

    I get the same result from the BASIC program. LBA1 = 0x80 which is 32768.

    RUN
    LBA0 ? 40
    LBA1 ? 128
    LBA2 ? 0
    SD CTRLR STAT = 128
    20 31 30 30 20 52 45 4D 20 54 45 53 54 20 55 50   100 REM TEST UP
    50 45 52 20 4D 45 4D 4F 52 59 0D 0A 20 31 31 30  PER MEMORY.. 110
    20 52 45 4D 20 55 50 50 45 52 20 4D 45 4D 4F 52   REM UPPER MEMOR
    59 20 49 53 20 34 4B 42 20 46 52 4F 4D 20 24 45  Y IS 4KB FROM $E
    30 30 30 2D 24 45 46 46 46 20 28 35 37 33 34 34  000-$EFFF (57344
    2D 36 31 34 33 39 20 44 45 43 29 0D 0A 20 31 32  -61439 DEC).. 12
    30 20 53 3D 35 37 33 34 34 0D 0A 20 31 33 30 20  0 S=57344.. 130
    45 3D 36 31 34 33 39 0D 0A 20 32 30 30 20 52 45  E=61439.. 200 RE
    4D 20 46 49 4C 4C 20 4D 45 4D 4F 52 59 0D 0A 20  M FILL MEMORY..
    32 31 30 20 50 3D 30 0D 0A 20 32 32 30 20 46 4F  210 P=0.. 220 FO
    52 20 41 3D 53 20 54 4F 20 45 0D 0A 20 32 33 30  R A=S TO E.. 230
    20 50 4F 4B 45 20 41 2C 50 0D 0A 20 32 34 30 20   POKE A,P.. 240
    50 3D 50 2B 31 0D 0A 20 32 35 30 20 50 3D 50 20  P=P+1.. 250 P=P
    41 4E 44 20 32 35 35 0D 0A 20 32 36 30 20 4E 45  AND 255.. 260 NE
    58 54 20 41 0D 0A 20 33 30 30 20 52 45 4D 20 56  XT A.. 300 REM V
    45 52 49 46 59 20 46 49 4C 4C 45 44 20 4D 45 4D  ERIFY FILLED MEM
    4F 52 59 0D 0A 20 33 31 30 20 58 3D 30 0D 0A 20  ORY.. 310 X=0..
    33 32 30 20 46 4F 52 20 41 3D 53 20 54 4F 20 45  320 FOR A=S TO E
    0D 0A 20 33 33 30 20 50 3D 50 45 45 4B 28 41 29 .....
    Read more »

  • Parsing the Boot Sector

    land-boards.com08/04/2020 at 10:56 0 comments

    Notes on parsing the boot sector of the SD Card with the goal of reading in the directory.

    The boot sector is documented in this log

    The first important data structure on a FAT volume is called the BPB (BIOS Parameter Block), 
    which is located in the first sector of the volume in the Reserved Region. 
    This sector is sometimes called the “boot sector” or the “reserved sector” or the “0th sector,” 
    but the important fact is simply that it is the first sector of the volume.
    
    All the fields whose names start with BPB_ are part of the BPB.

     Significant locations are <values in brackets are what I read from my SD Card>:

    14-15 BPB_RsvdSecCnt
          Number of reserved sectors (1)
          FAT32 uses 32.
          <0x083a> = 2106 decimal
    16    BPB_NumFATs
          Number of FAT copies
          <0x02>
    36-39 BPB_FATSz32
          Sectors per FAT
          <0x00003BE3> = 15331 dec
    

    FirstDataSector = BPB_RsvdSecCnt + (BPB_NumFATs * BPB_FATSz32) + RootDirSectors;

                              For FAT32, RootDirSectors = 0

                               = 2106 + (2 * 15331) + 0

                               = 32,768

    The sector there is:

    Batch file to compile and make files:

    cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -vm -m OSISDOS.map -o OSISDOS.o OSISDOS.c
    "C:\Users\HPz420\Documents\GitHub\Doug Gilliland\Retro-Computers\6502\RetroAssembler\retroassembler.exe" -d -D=0x0300 OSISDOS.o OSISDOS.DIS
    "..\..\..\..\..\PC Tools\srecord\srec_cat.exe" OSISDOS.o -bin -of 0x300 -o OSISDOS.c1p -os -esa=0x300
    

    Got the code to read the directory working in C. It is convenient that the endianness of the values matches what reading longs and shorts in C use so there's no need to shuffle the endian values or read as bytes and pack into shorts and long values.

    /* main - Test the SD Card interface                                */
    void main(void)
    {
        unsigned long dirSectorNumber;
        unsigned short sectorCount;
        unsigned char numFATs;
        unsigned long FATSz;
        *(unsigned char*) BANK_SELECT_REG_ADR = 0x00;    /* Set bank register to first bank */
        readSector((unsigned long)0);        /* Master boot record at sector 0 */
        /* Get the sector count, number of FATs, and FAt size    */
        sectorCount = * (unsigned long *) (READ_BUFFER_START + BPB_RsvdSecCnt_16);
        numFATs = * (unsigned char *) (READ_BUFFER_START + BPB_NumFATs_8);
        FATSz = * (unsigned long *) (READ_BUFFER_START + BPB_FATSz32_32);
        /* Assumes that numFATs = 2 */
        /* Do the math to find the directory sector                */
        dirSectorNumber = sectorCount + (FATSz << 1);    
        /* Read the directory into the bank SRAM*/
        readSector(dirSectorNumber);
    }
    

    Next step is to go from the directory to a file.

  • SD Card Reading Works!

    land-boards.com08/03/2020 at 23:56 0 comments

    I had the wrong address for the SD controller registers in my code. Fixed it and it works now.

    The C code reads a 512 byte block from sector 0 into SRAM starting at 0xE000 (Bank 0).

    /* OSISDOS.c - Minimal Operating System for OSI C1P/SuperBoard ][     */
    /* SDHC card based disk operating system                            */
    /* 8KB Microsoft BASIC-In-ROM has I/O support routines                */
    /* CEGMON has various hooks to the I/O in BASIC                        */
    /* Uses Banked SRAM from $E000-$EFFF to buffer SD card data.        */
    /* Intended to fit within a small ROM space below CEGMON            */
    /*    Target ROM space goes from $F100-$F7FF (1.75kb)                    */
    /*                                                                    */
    /* Compiled using CC65 toolchain                                     */
    
    /* 
    Memory Map
        $0000-$9FFF - SRAM (40KB)
        $A000-$BFFF - Microsoft BASIC-in-ROM (8KB)
            $D000-$D3FF - 1KB Display RAM
            $DC00 - PS/2 Keyboard
            $E000-$EFFF - Bank Selectable SRAM (not detectable as BASIC RAM)
            $F000-$FFFF - CEGMON Monitor ROM 4K
            $F000-$F001 - ACIA (UART) 61440-61441 dec
            $F002 - J6 I/O Connector 61442 dec
            $F003 - J8 I/O Connector 61443 dec
         $F004 - LEDS 61444 dec
            d0-d1 LEDs are on the FPGA card
         $F005 - Bank Select Register 61445 dec
            d0..d3 used for 128KB SRAMs
        $F010-$F017 - SD card
               0    SDDATA        read/write data
            1    SDSTATUS      read
            1    SDCONTROL     write
            2    SDLBA0        write-only
            3    SDLBA1        write-only
            4    SDLBA2        write-only (only bits 6:0 are valid)
    */
    
    //#include "osic1p.h"
    
    #define READ_BUFFER_START    0xE000    /* Banked SRAM            */
    #define WRITE_BUFFER_START    0xE200    
    #define LED_BITS_01            0xF004
    #define BANK_SELECT_REG_ADR    0xF005
    #define START_BANKED_RAM     0xE000
    #define SD_DATA                0xF010
    #define SD_CTRL                0xF011
    #define SD_STATUS            0xF011
    #define SD_LBA0                0xF012
    #define SD_LBA1                0xF013
    #define SD_LBA2                0xF014
    #define READ_COMMMAND        0x00
    #define WRITE_COMMMAND        0x01
    
    extern void main(void);
    extern void setLBA0(unsigned char);
    extern void setLBA1(unsigned char);
    extern void setLBA2(unsigned char);
    extern void readBlock(void);
    
    /* main - Test the SD Card interface                                */
    void main(void)
    {
        /* Set to first bank of the banked SRAM */ 
        *(unsigned char*) BANK_SELECT_REG_ADR = 0x00;
        setLBA0(0);
        setLBA1(0);
        setLBA2(0);
        readBlock();
    }
    
    /* issueSDCardCommand - Send read or write command to SD Card        */
    void issueSDCardCommand(unsigned char rwCmd)
    {
        *(unsigned char *) SD_CTRL = rwCmd;
    }
    
    /* setLBA0 - Set the least significant logical block address bits    */
    void setLBA0(unsigned char lba0)
    {
        *(unsigned char *) SD_LBA0 = lba0;
    }
    
    /* setLBA1 - Set the middle 8 bits of the logical block addr bits    */
    void setLBA1(unsigned char lba1)
    {
        *(unsigned char *) SD_LBA1 = lba1; 
    }
    
    /* setLBA2 - Set the upper 8 bits of the logical block addr bits    */
    void setLBA2(unsigned char lba2)
    {
        *(unsigned char *) SD_LBA2 = lba2;
    }
    
    /* waitSDCardReady - Wait for the SD Card to be ready                */
    void waitSDCardReady(void)
    {
        * (unsigned char *) LED_BITS_01 = 0x1;
        while (*(unsigned char *) SD_STATUS != 0x80);
        * (unsigned char *) LED_BITS_01 = 0x0;
    }
    
    /* waitSDCardRcvDataReady - Wait for the SD Card to have data ready    */
    void waitSDCardRcvDataReady(void)
    {
        while (*(unsigned char *) SD_STATUS != 0xE0);
    }
    
    /* waitSDCardTxDataEmpty - Wait for transmit ready from SD ctrlr    */
    void waitSDCardTxDataEmpty(void)
    {
        while (*(unsigned char *) SD_STATUS != 0xA0);
    }
    
    /* readByteFromSDCard - Read a byte from the SD Card                */
    unsigned char readByteFromSDCard(void)
    {
        char rdChar;
        waitSDCardRcvDataReady();
        rdChar = *(unsigned char *) SD_DATA;
        return(rdChar);
    }
    
    /* writeByteToSDCard - Write a byte to the SD Card                    */
    void writeByteToSDCard(unsigned char outChar)
    {
        waitSDCardTxDataEmpty();
        *(unsigned char *) SD_DATA = outChar;
    }
    
    /* readBlock - -Read a block from the SD Card                        */
    void readBlock(void)
    {
        unsigned short loopCount;
        unsigned char * inBuffer;
        inBuffer = (unsigned char *) READ_BUFFER_START;
        waitSDCardReady();
        issueSDCardCommand(READ_COMMMAND);
        for (loopCount = 0; loopCount < 512; loopCount++)
        {
            *inBuffer++ = readByteFromSDCard();
        }
    }
    
    /* writeBlock - Write a block to the SD Card                        */
    void writeBlock(void)
    {
        unsigned short loopCount;
        unsigned char * outBuffer;
        outBuffer = (unsigned...
    Read more »

  • SD Card Code

    land-boards.com07/31/2020 at 20:28 0 comments

    Minimal SD card code in C:

    /* OSISDOS.c - Minimal Operating System for OSI C1P/SuperBoard ][ 	*/
    /* SDHC card based disk operating system							*/
    /* 8KB Microsoft BASIC-In-ROM has I/O support routines				*/
    /* CEGMON has various hooks to the I/O in BASIC						*/
    /* Uses Banked SRAM from $E000-$EFFF to buffer SD card data.		*/
    /* Intended to fit within a small ROM space below CEGMON			*/
    /*	Target ROM space goes from $F100-$F7FF (1.75kb)					*/
    /*																	*/
    /* Compiled using CC65 toolchain 									*/
    
    /* 
    Memory Map
    	$0000-$9FFF - SRAM (40KB)
    	$A000-$BFFF - Microsoft BASIC-in-ROM (8KB)
    		$D000-$D3FF - 1KB Display RAM
    		$DC00 - PS/2 Keyboard
    		$E000-$EFFF - Bank Selectable SRAM (not detectable as BASIC RAM)
    		$F000-$FFFF - CEGMON Monitor ROM 4K
    		$F000-$F001 - ACIA (UART) 61440-61441 dec
    		$F002 - J6 I/O Connector 61442 dec
    		$F003 - J8 I/O Connector 61443 dec
     	$F004 - LEDS 61444 dec
    		d0-d1 LEDs are on the FPGA card
     	$F005 - Bank Select Register 61445 dec
    		d0..d3 used for 128KB SRAMs
    	$F010-$F017 - SD card
    	   	0    SDDATA        read/write data
    		1    SDSTATUS      read
    		1    SDCONTROL     write
    		2    SDLBA0        write-only
    		3    SDLBA1        write-only
    		4    SDLBA2        write-only (only bits 6:0 are valid)
    */
    
    //#include "osic1p.h"
    
    #define READ_BUFFER_START	0xE000	/* Banked SRAM			*/
    #define WRITE_BUFFER_START	0xE200	
    #define BANK_SELECT_REG_ADR	0xF005
    #define START_BANKED_RAM 	0xE000
    #define SD_DATA				0xF000
    #define SD_CTRL				0xF001
    #define SD_STATUS			0xF001
    #define SD_LBA0				0xF002
    #define SD_LBA1				0xF003
    #define SD_LBA2				0xF004
    #define READ_COMMMAND		0x00
    #define WRITE_COMMMAND		0x01
    
    /* issueSDCardCommand - Send read or write command to SD Card		*/
    void issueSDCardCommand(unsigned char rwCmd)
    {
    	*(unsigned char *) SD_CTRL = rwCmd;
    }
    
    /* setLBA0 - Set the least significant logical block address bits	*/
    void setLBA0(unsigned char lba0)
    {
    	*(unsigned char *) SD_LBA0 = lba0;
    }
    
    /* setLBA1 - Set the middle 8 bits of the logical block addr bits	*/
    void setLBA1(unsigned char lba1)
    {
    	*(unsigned char *) SD_LBA1 = lba1; 
    }
    
    /* setLBA2 - Set the upper 8 bits of the logical block addr bits	*/
    void setLBA2(unsigned char lba2)
    {
    	*(unsigned char *) SD_LBA2 = lba2;
    }
    
    /* waitSDCardReady - Wait for the SD Card to be ready				*/
    void waitSDCardReady(void)
    {
    	while (*(unsigned char *) SD_STATUS != 0x80);
    }
    
    /* waitSDCardRcvDataReady - Wait for the SD Card to have data ready	*/
    void waitSDCardRcvDataReady(void)
    {
    	while (*(unsigned char *) SD_STATUS != 0xE0);
    }
    
    /* waitSDCardTxDataEmpty - Wait for transmit ready from SD ctrlr	*/
    void waitSDCardTxDataEmpty(void)
    {
    	while (*(unsigned char *) SD_STATUS != 0xA0);
    }
    
    /* readByteFromSDCard - Read a byte from the SD Card				*/
    unsigned char readByteFromSDCard(void)
    {
    	char rdChar;
    	waitSDCardRcvDataReady();
    	rdChar = *(unsigned char *) SD_DATA;
    	return(rdChar);
    }
    
    /* writeByteToSDCard - Write a byte to the SD Card					*/
    void writeByteToSDCard(unsigned char outChar)
    {
    	waitSDCardTxDataEmpty();
    	*(unsigned char *) SD_DATA = outChar;
    }
    
    /* readBlock - -Read a block from the SD Card						*/
    void readBlock(void)
    {
    	unsigned short loopCount;
    	unsigned char * inBuffer;
    	inBuffer = (unsigned char *) READ_BUFFER_START;
    	waitSDCardReady();
    	issueSDCardCommand(READ_COMMMAND);
    	for (loopCount = 0; loopCount < 512; loopCount++)
    	{
    		*inBuffer++ = readByteFromSDCard();
    	}
    }
    
    /* writeBlock - Write a block to the SD Card						*/
    void writeBlock(void)
    {
    	unsigned short loopCount;
    	unsigned char * outBuffer;
    	outBuffer = (unsigned char *) WRITE_BUFFER_START;
    	waitSDCardReady();
    	issueSDCardCommand(WRITE_COMMMAND);
    	for (loopCount = 0; loopCount < 512; loopCount++)
    	{
    		writeByteToSDCard(*outBuffer++);
    	}
    }
    
    /* main - Test the SD Card interface								*/
    void main(void)
    {
    	/* Set to first bank of the banked SRAM */ 
    	*(unsigned char*) BANK_SELECT_REG_ADR = 0x00;
    	setLBA0(0);
    	setLBA1(0);
    	setLBA2(0);
    	readBlock();
    }
    

     Assembly output list file:

    ca65 V2.17 - Git de519b9
    Main file   : OSISDOS.s
    Current file: OSISDOS.s
    
    000000r 1               ;
    000000r 1...
    Read more »

  • CC65 Toolchain for OSI C1P

    land-boards.com07/29/2020 at 11:31 0 comments

    I want to write the OS for the SD Card (OSISDOS) in C so it can be ported to other hardware platforms.

    I tried to get the CC65 Assembler to work in a previous log and gave up. Let's try again. Here's the doc page (Ohio Scientific-specific information for cc65). From the page:

    • The target "osic1p" is implemented
    • The standard binary output format generated by the linker for the osic1p target is a pure machine language program.
    • Example for converting an executable "hello" file that was built for the default start address $0200 to an uploadable file "hello.c1p":
      srec_cat hello -bin -of 0x200 -o hello.c1p -os -esa=0x200
    • By default programs compiled for the osic1p target are configured for 32 kB RAM. The RAM size can be configured via the symbol __HIMEM__.
    • The default start address is $0200. The start address is configurable via the linker option --start-addr.
    • The C runtime stack is located at the top of RAM and growing downwards. The size is configurable via the symbol __STACKSIZE__. The default stack size is $0400.
    • The C heap is located at the end of the program and grows towards the C runtime stack.
    • Example for building a program with start address $0300, stack size $0200 and RAM size $2000:
      cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p hello.c
    • Default config file (osic1p.cfg)
    • This configuration is made for assembler programmers who don't need a special setup.
      To use this config file, assemble with -t osic1p and link with -C osic1p-asm.cfg. The former will make sure that correct runtime library is used, while the latter supplies the actual config. When using cl65, use both command line options. Sample command lines for cl65:
    •   cl65 -t osic1p -C osic1p-asm.cfg -o program source.s cl65 -t osic1p -C osic1p-asm.cfg -u __BOOT__ -o program.lod source.s
    • Programs containing Ohio Scientific-specific code may use the osic1p.h header file.
    • There is a module screen-c1p-24x24.o in the OSI-specific cc65 runtime library that contains all conio functions that depend on the screen layout. No further configuration is needed for using the default screen layout of the Challenger 1P.
    • There is no support for stdio
    • The program return code has no effect. When the main() function finishes, the boot prompt is shown again.

    References

    Added bin folder of cc65 to PATH env vars.

    Using Command line:

    cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -o OSISDOS.o OSISDOS.c

     Create a list file:

    cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -l osidos.lst OSISDOS.c

    No errors 

    Looking at command line options

    --start-addr 0x300 = Set the default start address
    
    -Wl = Pass options directly to the linker. 
    This may be used to pass options that aren't directly supported by cl65. 
    Several options may be separated by commas; the commas are replaced by spaces 
    when passing them to the linker.
    
    -D,__HIMEM__=$2000, = Define a preprocessor symbol - 16K High Memory
    
    -D,__STACKSIZE__=$0200  = Define a preprocessor symbol - 512 byte stack
    
    -t  osic1p = Set the target system - ISI C1P target

    Change format

    "..\..\..\..\..\PC Tools\srecord\srec_cat.exe" OSISDOS -bin -of 0x300 -o OSISDOS.c1p -os -esa=0x300

    Output looks like:

    .0300/A2
    FF
    9A
    D8
    A9
    00
    A2
    ...

    Very nice!

    Except this doesn't match the list file. Disassemble the object file using retroassembler disassemble function:

    "C:\Users\HPz420\Documents\GitHub\Doug Gilliland\Retro-Computers\6502\RetroAssembler\retroassembler.exe" -d -D=0x0300 OSISDOS.o OSISDOS.DIS

    The top of the file looks like:

    $0300 a2 ff      ldx #$ff
    $0302 9a         txs
    $0303 d8         cld
    $0304 a9 00      lda #$00
    $0306 a2 20      ldx #$20
    $0308 85 02      sta $02
    $030a 86 03      stx $03
    $030c 20 9b 05   jsr $059b
    $030f 20 1b 03   jsr $031b
    $0312 20 27 03 jsr...
    Read more »

  • Tried new SDHC card and it works

    land-boards.com07/26/2020 at 01:47 0 comments

    Not sure if there's something wrong with the other SD card, but I tried a couple of other cards and they worked fine. Here's the capture from the BASIC program.

    BASIC Code:

     100 REM OSISDOS PROTOTYPE READ SD CARD IN BASIC
     110 SAVE:REM TURN ON LOGGING TO SERIAL PORT
     120 REM SDCARD BASE ADDRESS = $F010 (61456 DEC)
     130 DT=61456:REM SDDAT
     140 ST=61457:REM SDSTATUS/SDCONTROL
     150 A0=61458:REM SDLBA0
     160 A1=61459:REM SDLBA1
     170 A2=61460:REM SDLBA2
     180 DIM MA(512):REM RESERVE ARRAY SPACE FOR SD CARD DATA
     200 REM INPUT THE LBA VALUES AND WRITE TO SD CTRLR REGISTERS
     210 INPUT "LBA0 ";L0
     220 POKE A0,L0
     230 INPUT "LBA1 ";L1
     240 POKE A1,L1
     250 INPUT "LBA2 ";L2
     260 POKE A2,L2
     300 REM CHECK SD CTRLR STATUS, S/B 128
     310 SC=PEEK(ST)
     320 PRINT "SD CTRLR STAT =";SC
     330 IF SC<>128 GOTO 310
     350 REM WRITE 0 TO CONTROL REG FOR READ BLOCK
     360 POKE ST,0
     400 REM WAIT FOR READ VALUE READY
     410 REM READ SD CARD INTO ARRAY
     420 FOR MO=0 TO 511
     430 SV=PEEK(ST)
     440 IF SV <> 224 GOTO 430
     450 MA(MO)=PEEK(DT)
     460 NEXT MO
     500 REM DUMP ARRAY TO SCREEN
     510 FOR I=0 TO 31
     515 SA=(I*16)
     520 FOR J=0 TO 15
     530 DV=MA(SA+J)
     540 GOSUB 600
     560 NEXT J
     570 GOSUB 800 
     580 NEXT I
     590 END
     600 REM PRINT DECIMAL NUMBER AS TWO HEX DIGITS
     610 NB=(DV AND 240)/16
     620 GOSUB 670
     630 NB=DV AND 15
     640 GOSUB 670
     650 PRINT " ";
     660 RETURN
     670 IF NB>9 GOTO 710
     680 VL=NB+48
     690 PRINT CHR$(VL);
     700 RETURN
     710 VL=NB+55
     720 PRINT CHR$(VL);
     730 RETURN
     800 PRINT " ";
     810 FOR OF=SA TO (SA+15)
     820 IF MA(OF)<32 THEN PRINT ".";
     830 IF MA(OF)>126 THEN PRINT ".";
     840 IF MA(OF)>31 AND MA(OF)<127 THEN PRINT CHR$(MA(OF));
     850 NEXT OF
     860 PRINT
     870 RETURN

  • Added Banked SRAM

    land-boards.com07/25/2020 at 14:48 0 comments

    The EP2C5-DB has an external 128 KB SRAM but the design only uses 40KB. The 40KB limitation is due to the original address map which places BASIC in ROM starting at $A000. It might be possible to move the BASIC, but probably not worth the effort. I doubt there's any code out there that uses more than 40KB.

    Open Memory Map Addresses

    There's two open address ranges from $C000 to $CFFF and $E000 to $EFFF. When I tried putting SRAM into the $Cxxx range the board did not boot. But when I put SRAM into the $Exxx range the board booted fine. I wrote a little program to test the expansion SRAM and it worked well.

     100 REM TEST UPPER MEMORY
     110 REM UPPER MEMORY IS 4KB FROM $E000-$EFFF (57344-61439 DEC)
     120 S=57344
     130 E=61439
     200 REM FILL MEMORY
     210 P=0
     220 FOR A=S TO E
     230 POKE A,P
     240 P=P+1
     250 P=P AND 255
     260 NEXT A
     300 REM VERIFY FILLED MEMORY
     310 X=0
     320 FOR A=S TO E
     330 P=PEEK(A)
     340 IF P<>X GOTO 500
     350 X=X+1
     360 X=X AND 255
     370 NEXT A
     380 END
     500 PRINT"ERROR"
     510 END
    

    Making a Banked RAM

    I thought it might be interesting to use the unused 64KB of SRAM as a banked SRAM. The 4KB section at $Exxx would allow for 16 banks of 4KB each. Although BASIC doesn't support the RAM as program space it still could be used for storing data for the OSISDOS. And this was a nice diversion from being stuck with the SD card read problems (last log entry).

    In the original design, the A16 line from the EP2C5 FPGA to the SRAM is always set to 0. To add banking the A16 line needs to get set to 1 when the CPU address starts with $Exxx. Address lines A15..A12 then come from a bank register for accesses to 0xE****. The bank register is mapped to the I/O space. 

    Wrote a simple test program to verify that different data is written into each bank:

     100 REM TEST BANKS
     110 REM UPPER MEMORY IS 4KB FROM $E000-$EFFF (57344-61439 DEC)
     120 S=57344:REM START OF SRAM BANK
     130 E=61439:REM END OF SRAM BANK
     140 B=61445:REM BANK SELECT REGISTER
     150 FOR V=0 TO 15:REM CHECK ALL 16 BANKS
     160 POKE B,V:REM WRITE TO BANK REGISTER
     170 POKE S,V:REM WRITE THE BANK NUMBER TO FIRST SRAM LOCATION
     180 NEXT V
     200 FOR V=0 TO 15:REM CHECK ALL 16 BANKS
     210 POKE B,V:REM WRITE TO BANK REGISTER
     220 R=PEEK(S):REM READ BACK THE SRAM
     230 IF R<>V GOTO 300: COMPARE TO VALUE WRITTEN
     230 NEXT V
     240 PRINT "PASSED"
     250 END
     300 PRINT "ERROR"

     Took a bit to get it working but it does now work.  This much SRAM would have been unimaginable back in the day.

View all 16 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates