-
OSISDOS Command Line
08/08/2020 at 17:10 • 0 commentsNow 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
08/08/2020 at 11:38 • 0 commentsNow 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 := $D040 ; Base of C1P video RAM C1P_VRAM_SIZE = $0400 ; Size of C1P video RAM (1 kB) C1P_SCR_WIDTH = $30 ; Screen width (48) C1P_SCR_HEIGHT = $10 ; Screen height (16) C1P_SCR_FIRSTCHAR = $0b ; Offset of cursor position (0, 0) from base ; of video RAM C1P_SCROLL_DIST = $40 ; Memory distance for scrolling by one line (48 chars/line) osi_screen_funcs C1P_SCR_BASE, C1P_VRAM_SIZE, C1P_SCR_FIRSTCHAR, \ C1P_SCR_WIDTH, C1P_SCR_HEIGHT, C1P_SCROLL_DIST
The library does not have to be rebuilt for the C1P since the over-ride is on the command line for cl65. This also requires a couple of other files from the GitHub source tree osiscreen.inc and extzp.inc. The new command lines are:
cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -vm -m hello.map --listing hello.lst -o hello.o screen-c1p-48x16.s hello.c "..\..\..\PC Tools\srecord\srec_cat.exe" hello.o -bin -of 0x300 -o hello.c1p -os -esa=0x300 "C:\Users\HPz420\Documents\GitHub\Doug Gilliland\Retro-Computers\6502\RetroAssembler\retroassembler.exe" -d -D=0x0300 hello.o hello.DIS
That did compile without error.
Problems
The screen code seemed flakey. Sometimes it worked and other times it failed to work. The function cgetc() seems to always work fine.
After some fine tuning of screen-c1p-48x16.s it seems to be much more reliable.
Code Size
The code generated is around 0xd00 long or just under 4 KB.
-
From the Directory to the File
08/05/2020 at 22:39 • 0 commentsIn 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
Name Offset (byte) Size (bytes) Description DIR_Name 0 11 Short name.
<RAMTEST BAS>DIR_Attr 11 1 File 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_NTRes 12 1 Reserved 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_CrtTimeTenth 13 1 Millisecond 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_FstClusHI 20 2 High word of this entry’s first cluster number
(always 0 for a FAT12 or FAT16 volume).
<0x0000>DIR_WrtTime 22 2 Time of last write. Note that file creation is considered a write. <0x00DD> DIR_WrtDate 24 2 Date of last write. Note that file creation is considered a write. <0xF9A4> DIR_FstClusLO 26 2 Low word of this entry’s first cluster number.
<0x0007> = 7 decDIR_FileSize 28 4 32-bit DWORD holding this file’s size in bytes.
<0x0000019C> = 412 decSo, 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 .. 330 P=PEEK(A) 0D 0A 20 33 34 30 20 49 46 20 50 3C 3E 58 20 47 .. 340 IF P<>X G 4F 54 4F 20 35 30 30 0D 0A 20 33 35 30 20 58 3D OTO 500.. 350 X= 58 2B 31 0D 0A 20 33 36 30 20 58 3D 58 20 41 4E X+1.. 360 X=X AN 44 20 32 35 35 0D 0A 20 33 37 30 20 4E 45 58 54 D 255.. 370 NEXT 20 41 0D 0A 20 33 38 30 20 45 4E 44 0D 0A 20 35 A.. 380 END.. 5 30 30 20 50 52 49 4E 54 22 45 52 52 4F 52 22 0D 00 PRINT"ERROR". 0A 20 35 31 30 20 45 4E 44 0D 0A 20 00 00 00 00 . 510 END.. .... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
So, the sector number of a particular file on the SD Card from the directory is:
LBA = FirstDataSector + ((((DIR_FstClusHI << 16) + (DIR_FstClusHLo)) - 2) * BPB_SecPerClus )
For RAMTEST.BAS:
- FirstDataSector = 32,768 Found earlier when the first sector of the data was found
- DIR_FstClusHI = 0x0000 - High 16-bits of first cluster
- DIR_FstClusHLo = 0x0007 - Low 16-bits of first cluster
- BPB_SecPerClus = 0x08 - Sectors per cluster
So, the LBA for RAMTEST.BAS should be:
= 32,768 + * ( ( (0x0000<<16) + (0x0007) ) - 2) * 8)
= 32,768+40
= 32,808
Which is correct!
-
Parsing the Boot Sector
08/04/2020 at 10:56 • 0 commentsNotes 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!
08/03/2020 at 23:56 • 0 commentsI 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 char *) WRITE_BUFFER_START; waitSDCardReady(); issueSDCardCommand(WRITE_COMMMAND); for (loopCount = 0; loopCount < 512; loopCount++) { writeByteToSDCard(*outBuffer++); } }
The program starts at 0x0300.
Type TE000,E05F in CEGMON to dump the buffer to the screen. It worked.
Compiler commands are:
cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -vm -m OSISDOS.map -o OSISDOS.o OSISDOS.c "..\..\..\..\..\PC Tools\srecord\srec_cat.exe" OSISDOS.o -bin -of 0x300 -o OSISDOS.c1p -os -esa=0x300 "C:\Users\HPz420\Documents\GitHub\Doug Gilliland\Retro-Computers\6502\RetroAssembler\retroassembler.exe" -d -D=0x0300 OSISDOS.o OSISDOS.DIS
Now, on to figuring out the FAT32 DOS directory structure.
-
Debugging code using CEGMON
08/02/2020 at 17:40 • 0 commentsCEGMON has some minimal debugging facilities.
The code I am trying to run is on the previous log. The command line for cl65 is:
cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -vm -m OSISDOS.map -o OSISDOS.o OSISDOS.c
This generates a verbose map file. The map file has addresses for each of the functions. The relevant functions are:
_exit 000315 LA _init 000300 LA _issueSDCardCommand 0003DC LA _main 000327 RLA _readBlock 000371 LA _readByteFromSDCard 00041C LA _setLBA0 000341 LA _setLBA1 000351 LA _setLBA2 000361 LA _waitSDCardRcvDataReady 0003FC LA _waitSDCardReady 0003EC LA _waitSDCardTxDataEmpty 00040C LA _writeBlock 00044B LA _writeByteToSDCard 000438 LA
CEGMON has the ability to load code, run code and set a breakpoint in the code. CEGMON can also display memory.
To load code:
- Connect to the serial port on Multicomp using Putty (115,200 baud, XON/XOFF handshake)
- Boot the Multicomp C1P
- Select M on the C1P keyboard the for Machine Code monitor
- Enter L on the C1P keyboard
- Copy/paste the .c1p file into a terminal window
- The code will start to run at 0x0300
- Should the program return to the monitor when the code is complete?
To run code enter the address (4-digits) then G for Go.
Debug Using Breakpoints
To debug code, insert a breakpoint at the address to stop at by entering Zaaaa where aaaa is the address to insert the breakpoint at. Then enter 0300G for Go at address 0x0300. The program will run until it hits the breakpoint and then will return to the Monitor prompt and display 00E0/aa. From the CEGMON manual:
At this point another breakpoint can be set using the Zaaaa as above.
Enter R to (re)start running from the breakpoint.
To dump a block of memory, use Taaaa,bbbb where aaaa is the start address and bbbb is the end address. CEGMON will insert the comma between the two numbers.
-
SD Card Assembly Language Code
07/31/2020 at 20:28 • 0 commentsMinimal 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 ; File generated by cc65 v 2.17 - Git de519b9 000000r 1 ; 000000r 1 .fopt compiler,"cc65 v 2.17 - Git de519b9" 000000r 1 .setcpu "6502" 000000r 1 .smart on 000000r 1 .autoimport on 000000r 1 .case on 000000r 1 .debuginfo off 000000r 1 .importzp sp, sreg, regsave, regbank 000000r 1 .importzp tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4 000000r 1 .macpack longbranch 000000r 2 .macro jeq Target 000000r 2 .if .match(Target, 0) 000000r 2 bne *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 beq Target 000000r 2 .else 000000r 2 bne *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 .macro jne Target 000000r 2 .if .match(Target, 0) 000000r 2 beq *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 bne Target 000000r 2 .else 000000r 2 beq *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 .macro jmi Target 000000r 2 .if .match(Target, 0) 000000r 2 bpl *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 bmi Target 000000r 2 .else 000000r 2 bpl *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 .macro jpl Target 000000r 2 .if .match(Target, 0) 000000r 2 bmi *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 bpl Target 000000r 2 .else 000000r 2 bmi *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 .macro jcs Target 000000r 2 .if .match(Target, 0) 000000r 2 bcc *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 bcs Target 000000r 2 .else 000000r 2 bcc *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 .macro jcc Target 000000r 2 .if .match(Target, 0) 000000r 2 bcs *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 bcc Target 000000r 2 .else 000000r 2 bcs *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 .macro jvs Target 000000r 2 .if .match(Target, 0) 000000r 2 bvc *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 bvs Target 000000r 2 .else 000000r 2 bvc *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 .macro jvc Target 000000r 2 .if .match(Target, 0) 000000r 2 bvs *+5 000000r 2 jmp Target 000000r 2 .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127) 000000r 2 bvc Target 000000r 2 .else 000000r 2 bvs *+5 000000r 2 jmp Target 000000r 2 .endif 000000r 2 .endmacro 000000r 2 000000r 1 .forceimport __STARTUP__ 000000r 1 .export _issueSDCardCommand 000000r 1 .export _setLBA0 000000r 1 .export _setLBA1 000000r 1 .export _setLBA2 000000r 1 .export _waitSDCardReady 000000r 1 .export _waitSDCardRcvDataReady 000000r 1 .export _waitSDCardTxDataEmpty 000000r 1 .export _readByteFromSDCard 000000r 1 .export _writeByteToSDCard 000000r 1 .export _readBlock 000000r 1 .export _writeBlock 000000r 1 .export _main 000000r 1 000000r 1 ; --------------------------------------------------------------- 000000r 1 ; void __near__ issueSDCardCommand (unsigned char) 000000r 1 ; --------------------------------------------------------------- 000000r 1 000000r 1 .segment "CODE" 000000r 1 000000r 1 .proc _issueSDCardCommand: near 000000r 1 000000r 1 .segment "CODE" 000000r 1 000000r 1 20 rr rr jsr pusha 000003r 1 A0 00 ldy #$00 000005r 1 A2 00 ldx #$00 000007r 1 B1 rr lda (sp),y 000009r 1 8D 01 F0 sta $F001 00000Cr 1 20 rr rr jsr incsp1 00000Fr 1 60 rts 000010r 1 000010r 1 .endproc 000010r 1 000010r 1 ; --------------------------------------------------------------- 000010r 1 ; void __near__ setLBA0 (unsigned char) 000010r 1 ; --------------------------------------------------------------- 000010r 1 000010r 1 .segment "CODE" 000010r 1 000010r 1 .proc _setLBA0: near 000010r 1 000010r 1 .segment "CODE" 000010r 1 000010r 1 20 rr rr jsr pusha 000013r 1 A0 00 ldy #$00 000015r 1 A2 00 ldx #$00 000017r 1 B1 rr lda (sp),y 000019r 1 8D 02 F0 sta $F002 00001Cr 1 20 rr rr jsr incsp1 00001Fr 1 60 rts 000020r 1 000020r 1 .endproc 000020r 1 000020r 1 ; --------------------------------------------------------------- 000020r 1 ; void __near__ setLBA1 (unsigned char) 000020r 1 ; --------------------------------------------------------------- 000020r 1 000020r 1 .segment "CODE" 000020r 1 000020r 1 .proc _setLBA1: near 000020r 1 000020r 1 .segment "CODE" 000020r 1 000020r 1 20 rr rr jsr pusha 000023r 1 A0 00 ldy #$00 000025r 1 A2 00 ldx #$00 000027r 1 B1 rr lda (sp),y 000029r 1 8D 03 F0 sta $F003 00002Cr 1 20 rr rr jsr incsp1 00002Fr 1 60 rts 000030r 1 000030r 1 .endproc 000030r 1 000030r 1 ; --------------------------------------------------------------- 000030r 1 ; void __near__ setLBA2 (unsigned char) 000030r 1 ; --------------------------------------------------------------- 000030r 1 000030r 1 .segment "CODE" 000030r 1 000030r 1 .proc _setLBA2: near 000030r 1 000030r 1 .segment "CODE" 000030r 1 000030r 1 20 rr rr jsr pusha 000033r 1 A0 00 ldy #$00 000035r 1 A2 00 ldx #$00 000037r 1 B1 rr lda (sp),y 000039r 1 8D 04 F0 sta $F004 00003Cr 1 20 rr rr jsr incsp1 00003Fr 1 60 rts 000040r 1 000040r 1 .endproc 000040r 1 000040r 1 ; --------------------------------------------------------------- 000040r 1 ; void __near__ waitSDCardReady (void) 000040r 1 ; --------------------------------------------------------------- 000040r 1 000040r 1 .segment "CODE" 000040r 1 000040r 1 .proc _waitSDCardReady: near 000040r 1 000040r 1 .segment "CODE" 000040r 1 000040r 1 4C rr rr jmp L000E 000043r 1 A2 00 L000E: ldx #$00 000045r 1 AD 01 F0 lda $F001 000048r 1 C9 80 cmp #$80 00004Ar 1 20 rr rr jsr boolne 00004Dr 1 D0 F4 jne L000E 00004Fr 1 60 rts 000050r 1 000050r 1 .endproc 000050r 1 000050r 1 ; --------------------------------------------------------------- 000050r 1 ; void __near__ waitSDCardRcvDataReady (void) 000050r 1 ; --------------------------------------------------------------- 000050r 1 000050r 1 .segment "CODE" 000050r 1 000050r 1 .proc _waitSDCardRcvDataReady: near 000050r 1 000050r 1 .segment "CODE" 000050r 1 000050r 1 4C rr rr jmp L0013 000053r 1 A2 00 L0013: ldx #$00 000055r 1 AD 01 F0 lda $F001 000058r 1 C9 E0 cmp #$E0 00005Ar 1 20 rr rr jsr boolne 00005Dr 1 D0 F4 jne L0013 00005Fr 1 60 rts 000060r 1 000060r 1 .endproc 000060r 1 000060r 1 ; --------------------------------------------------------------- 000060r 1 ; void __near__ waitSDCardTxDataEmpty (void) 000060r 1 ; --------------------------------------------------------------- 000060r 1 000060r 1 .segment "CODE" 000060r 1 000060r 1 .proc _waitSDCardTxDataEmpty: near 000060r 1 000060r 1 .segment "CODE" 000060r 1 000060r 1 4C rr rr jmp L0018 000063r 1 A2 00 L0018: ldx #$00 000065r 1 AD 01 F0 lda $F001 000068r 1 C9 A0 cmp #$A0 00006Ar 1 20 rr rr jsr boolne 00006Dr 1 D0 F4 jne L0018 00006Fr 1 60 rts 000070r 1 000070r 1 .endproc 000070r 1 000070r 1 ; --------------------------------------------------------------- 000070r 1 ; unsigned char __near__ readByteFromSDCard (void) 000070r 1 ; --------------------------------------------------------------- 000070r 1 000070r 1 .segment "CODE" 000070r 1 000070r 1 .proc _readByteFromSDCard: near 000070r 1 000070r 1 .segment "CODE" 000070r 1 000070r 1 20 rr rr jsr decsp1 000073r 1 20 rr rr jsr _waitSDCardRcvDataReady 000076r 1 A2 00 ldx #$00 000078r 1 AD 00 F0 lda $F000 00007Br 1 A0 00 ldy #$00 00007Dr 1 91 rr sta (sp),y 00007Fr 1 A0 00 ldy #$00 000081r 1 A2 00 ldx #$00 000083r 1 B1 rr lda (sp),y 000085r 1 4C rr rr jmp L001C 000088r 1 20 rr rr L001C: jsr incsp1 00008Br 1 60 rts 00008Cr 1 00008Cr 1 .endproc 00008Cr 1 00008Cr 1 ; --------------------------------------------------------------- 00008Cr 1 ; void __near__ writeByteToSDCard (unsigned char) 00008Cr 1 ; --------------------------------------------------------------- 00008Cr 1 00008Cr 1 .segment "CODE" 00008Cr 1 00008Cr 1 .proc _writeByteToSDCard: near 00008Cr 1 00008Cr 1 .segment "CODE" 00008Cr 1 00008Cr 1 20 rr rr jsr pusha 00008Fr 1 20 rr rr jsr _waitSDCardTxDataEmpty 000092r 1 A0 00 ldy #$00 000094r 1 A2 00 ldx #$00 000096r 1 B1 rr lda (sp),y 000098r 1 8D 00 F0 sta $F000 00009Br 1 20 rr rr jsr incsp1 00009Er 1 60 rts 00009Fr 1 00009Fr 1 .endproc 00009Fr 1 00009Fr 1 ; --------------------------------------------------------------- 00009Fr 1 ; void __near__ readBlock (void) 00009Fr 1 ; --------------------------------------------------------------- 00009Fr 1 00009Fr 1 .segment "CODE" 00009Fr 1 00009Fr 1 .proc _readBlock: near 00009Fr 1 00009Fr 1 .segment "CODE" 00009Fr 1 00009Fr 1 20 rr rr jsr decsp4 0000A2r 1 A2 E0 ldx #$E0 0000A4r 1 A9 00 lda #$00 0000A6r 1 A0 00 ldy #$00 0000A8r 1 20 rr rr jsr staxysp 0000ABr 1 20 rr rr jsr _waitSDCardReady 0000AEr 1 A9 00 lda #$00 0000B0r 1 20 rr rr jsr _issueSDCardCommand 0000B3r 1 A2 00 ldx #$00 0000B5r 1 A9 00 lda #$00 0000B7r 1 A0 02 ldy #$02 0000B9r 1 20 rr rr jsr staxysp 0000BCr 1 A0 03 L002C: ldy #$03 0000BEr 1 20 rr rr jsr ldaxysp 0000C1r 1 E0 02 cpx #$02 0000C3r 1 20 rr rr jsr boolult 0000C6r 1 F0 03 4C rr jne L002F 0000CAr 1 rr 0000CBr 1 4C rr rr jmp L002D 0000CEr 1 A0 01 L002F: ldy #$01 0000D0r 1 20 rr rr jsr ldaxysp 0000D3r 1 85 rr sta regsave 0000D5r 1 86 rr stx regsave+1 0000D7r 1 20 rr rr jsr incax1 0000DAr 1 A0 00 ldy #$00 0000DCr 1 20 rr rr jsr staxysp 0000DFr 1 A5 rr lda regsave 0000E1r 1 A6 rr ldx regsave+1 0000E3r 1 20 rr rr jsr pushax 0000E6r 1 20 rr rr jsr _readByteFromSDCard 0000E9r 1 A0 00 ldy #$00 0000EBr 1 20 rr rr jsr staspidx 0000EEr 1 A0 03 ldy #$03 0000F0r 1 20 rr rr jsr ldaxysp 0000F3r 1 85 rr sta regsave 0000F5r 1 86 rr stx regsave+1 0000F7r 1 20 rr rr jsr incax1 0000FAr 1 A0 02 ldy #$02 0000FCr 1 20 rr rr jsr staxysp 0000FFr 1 A5 rr lda regsave 000101r 1 A6 rr ldx regsave+1 000103r 1 4C rr rr jmp L002C 000106r 1 20 rr rr L002D: jsr incsp4 000109r 1 60 rts 00010Ar 1 00010Ar 1 .endproc 00010Ar 1 00010Ar 1 ; --------------------------------------------------------------- 00010Ar 1 ; void __near__ writeBlock (void) 00010Ar 1 ; --------------------------------------------------------------- 00010Ar 1 00010Ar 1 .segment "CODE" 00010Ar 1 00010Ar 1 .proc _writeBlock: near 00010Ar 1 00010Ar 1 .segment "CODE" 00010Ar 1 00010Ar 1 20 rr rr jsr decsp4 00010Dr 1 A2 E2 ldx #$E2 00010Fr 1 A9 00 lda #$00 000111r 1 A0 00 ldy #$00 000113r 1 20 rr rr jsr staxysp 000116r 1 20 rr rr jsr _waitSDCardReady 000119r 1 A9 01 lda #$01 00011Br 1 20 rr rr jsr _issueSDCardCommand 00011Er 1 A2 00 ldx #$00 000120r 1 A9 00 lda #$00 000122r 1 A0 02 ldy #$02 000124r 1 20 rr rr jsr staxysp 000127r 1 A0 03 L003C: ldy #$03 000129r 1 20 rr rr jsr ldaxysp 00012Cr 1 E0 02 cpx #$02 00012Er 1 20 rr rr jsr boolult 000131r 1 F0 03 4C rr jne L003F 000135r 1 rr 000136r 1 4C rr rr jmp L003D 000139r 1 A0 01 L003F: ldy #$01 00013Br 1 20 rr rr jsr ldaxysp 00013Er 1 85 rr sta regsave 000140r 1 86 rr stx regsave+1 000142r 1 20 rr rr jsr incax1 000145r 1 A0 00 ldy #$00 000147r 1 20 rr rr jsr staxysp 00014Ar 1 A5 rr lda regsave 00014Cr 1 A6 rr ldx regsave+1 00014Er 1 A0 00 ldy #$00 000150r 1 20 rr rr jsr ldauidx 000153r 1 20 rr rr jsr _writeByteToSDCard 000156r 1 A0 03 ldy #$03 000158r 1 20 rr rr jsr ldaxysp 00015Br 1 85 rr sta regsave 00015Dr 1 86 rr stx regsave+1 00015Fr 1 20 rr rr jsr incax1 000162r 1 A0 02 ldy #$02 000164r 1 20 rr rr jsr staxysp 000167r 1 A5 rr lda regsave 000169r 1 A6 rr ldx regsave+1 00016Br 1 4C rr rr jmp L003C 00016Er 1 20 rr rr L003D: jsr incsp4 000171r 1 60 rts 000172r 1 000172r 1 .endproc 000172r 1 000172r 1 ; --------------------------------------------------------------- 000172r 1 ; void __near__ main (void) 000172r 1 ; --------------------------------------------------------------- 000172r 1 000172r 1 .segment "CODE" 000172r 1 000172r 1 .proc _main: near 000172r 1 000172r 1 .segment "CODE" 000172r 1 000172r 1 A2 00 ldx #$00 000174r 1 A9 00 lda #$00 000176r 1 8D 05 F0 sta $F005 000179r 1 A9 00 lda #$00 00017Br 1 20 rr rr jsr _setLBA0 00017Er 1 A9 00 lda #$00 000180r 1 20 rr rr jsr _setLBA1 000183r 1 A9 00 lda #$00 000185r 1 20 rr rr jsr _setLBA2 000188r 1 20 rr rr jsr _readBlock 00018Br 1 60 rts 00018Cr 1 00018Cr 1 .endproc 00018Cr 1 00018Cr 1
main() starts at 0x172 from 0x300 or 0x472.
Nice!
-
CC65 Toolchain for OSI C1P
07/29/2020 at 11:31 • 0 commentsI 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 usingcl65
, use both command line options. Sample command lines forcl65
: -
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
- cc65 Main Page
- OSI C1P Specific
- CC65 Wiki page
- DOS command line toolchain (my GitHub)
- CC65 Source Code
- Windows Snapshot
- cc65 Documentation Overview
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 $0327 $0315 20 c1 04 jsr $04c1 $0318 4c 00 ff jmp $ff00 $031b a0 00 ldy #$00 $031d f0 07 beq $0326 $031f a9 27 lda #$27 $0321 a2 03 ldx #$03 $0323 4c be 05 jmp $05be $0326 60 rts
It's definitely 6502 code. Is that C1P startup code? The list file from cl65 has:
000000r 1 .forceimport __STARTUP__ 000000r 1 .export _main 000000r 1 .export _setLBA0 000000r 1 .export _setLBA1
Disappointing that the cl65 listing file does not contain all of the code that is created.
Create a map file using the line:
cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -m OSISDOS.map -o OSISDOS.o OSISDOS.c
Table shows where main() starts:
Exports list by name: --------------------- __BSS_RUN__ 0005E3 RLA __BSS_SIZE__ 000000 REA __CONSTRUCTOR_COUNT__ 000000 REA __CONSTRUCTOR_TABLE__ 000327 RLA __DESTRUCTOR_COUNT__ 000000 REA __DESTRUCTOR_TABLE__ 0005BE RLA __MAIN_SIZE__ 001B00 REA __MAIN_START__ 000300 RLA __STACKSIZE__ 000200 REA __STARTUP__ 000001 REA _main 000327 RLA addysp 0004B4 RLA boolne 00051E RLA boolult 00053D RLA decsp1 0004CD RLA decsp4 0004D6 RLA donelib 0004C1 RLA incax1 0004E3 RLA incsp1 0004EA RLA incsp2 0004F9 RLA incsp4 000507 RLA initlib 00031B RLA ldauidx 00050C RLA ldaxysp 000517 RLA ptr1 00000A RLZ pusha 00054E RLA pushax 000564 RLA regsave 000006 RLZ sp 000002 RLZ staspidx 00057A RLA staxysp 000592 RLA tmp1 000012 RLZ zerobss 00059B RLA
main() is at 0x0327. The code at 0x0327 is:
$0327 a2 00 ldx #$00 $0329 a9 00 lda #$00 $032b 8d 05 f0 sta $f005 $032e a9 00 lda #$00 $0330 20 41 03 jsr $0341 $0333 a9 00 lda #$00 $0335 20 51 03 jsr $0351
This does nicely match the main() code is the .lst file from cl65:
000000r 1 A2 00 ldx #$00 000002r 1 A9 00 lda #$00 000004r 1 8D 05 F0 sta $F005 000007r 1 A9 00 lda #$00 000009r 1 20 rr rr jsr _setLBA0 00000Cr 1 A9 00 lda #$00 00000Er 1 20 rr rr jsr _setLBA1 000011r 1 A9 00 lda #$00 000013r 1 20 rr rr jsr _setLBA2 000016r 1 20 rr rr jsr _readBlock 000019r 1 60 rts
A more detailed map file can be created using the command line:
cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p -vm -m OSISDOS.map -o OSISDOS.o OSISDOS.c
I will debug the code in another log.
-
Tried new SDHC card and it works
07/26/2020 at 01:47 • 0 commentsNot 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
07/25/2020 at 14:48 • 0 commentsThe 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.