-
Toochain Video
06/23/2022 at 23:15 • 0 commentsNice video
-
External SRAM
02/25/2022 at 20:53 • 0 commentsThe base card has 1MB of external SRAM. It requires 3 of the 50 MHz clocks which means the CPU runs at 16.7 MHz when accessing the external SRAM.
Other (internal) SRAM/ROM/Peripherals accesses take 2 of 50 MHz clocks which means the CPU runs at 25 MHz for these accesses.
Tweeked the design and it runs reliably now. Created TS2_V001 branch since it is stable. Reverted the change to the ACIA receive buffer RTS handshake depth threshold.
-
Running Forth
02/25/2022 at 20:27 • 0 comments -
GPIO - 19 Bits
02/24/2022 at 13:47 • 0 commentsAdded GPIO ports to FPGA design.
Features
- Input/Output ports
- 3 bit port
- (2) 8 bit ports
- Two locations from CPU
- Register/port selection - indirect
- Set bit direction
- Data port
- Register/port selection - indirect
- Connects to J2 connector
Indirect Register
-- 0 DAT0 bits [2:0] -- 1 DDR0 bits [2:0] -- 2 DAT2 bits [7:0] -- 3 DDR2 bits [7:0] -- 4 DAT3 bits [7:0] -- 5 DDR3 bits [7:0]
Data Direction Register Bits
-- 0 in the data direction register marks the bit as an output -- 1 in the data direction register marks it as an input
After reset, GPIOADR=0, all DDR*=0 (output) all DAT*=0 (output low).
Route to DB-25 on MultiComp in a Box design.
-
SD Card Support
02/24/2022 at 13:27 • 0 commentsAdded SD Card support. The SD card VHDL code comes from MultiComp.
Memory Map
-- 0x010050-0x010058F - SD Card -- 0x010051 - SDDATA read/write data -- 0x010053 - SDSTATUS read -- 0x010053 - SDCONTROL write -- 0x010055 - SDLBA0 write-only -- 0x010057 - SDLBA1 write-only -- 0x010059 - SDLBA2 write-only (only bits 6:0 are valid)
C Code to Read First SD Card Block to SRAM
// SDCard.c #define ACIASTAT (volatile unsigned char *) 0x010041 #define ACIADATA (volatile unsigned char *) 0x010043 #define VDUSTAT (volatile unsigned char *) 0x010040 #define VDUDATA (volatile unsigned char *) 0x010042 #define ACIA_TXRDYBIT 0x2 // SD Card #define SD_SDDATA_REG (volatile unsigned char *) 0x010051 #define SD_STATUS_REG (volatile unsigned char *) 0x010053 #define SD_CMD_REG (volatile unsigned char *) 0x010053 #define SD_LBA0_REG (volatile unsigned char *) 0x010055 #define SD_LBA1_REG (volatile unsigned char *) 0x010057 #define SD_LBA2_REG (volatile unsigned char *) 0x010059 // SD Card Status Reg #define SD_WR_RDY 0X80 #define SD_RD_RDY 0X40 #define SD_BLK_BUSY 0X20 #define SD_INIT_BUSY 0X10 // SD Card Control values #define SD_RD_BLK 0x00 #define SD_WR_BLK 0x01 #define BUFFER_START 0XE000 /* -- To read a 512-byte block from the SDCARD: -- Wait until SDSTATUS=0x80 (ensures previous cmd has completed) -- Write SDLBA0, SDLBA1 SDLBA2 to select block index to read from -- Write 0 to SDCONTROL to issue read command -- Loop 512 times: -- Wait until SDSTATUS=0xE0 (read byte ready, block busy) -- Read byte from SDDATA -- -- To write a 512-byte block to the SDCARD: -- Wait until SDSTATUS=0x80 (ensures previous cmd has completed) -- Write SDLBA0, SDLBA1 SDLBA2 to select block index to write to -- Write 1 to SDCONTROL to issue write command -- Loop 512 times: -- Wait until SDSTATUS=0xA0 (block busy) -- Write byte to SDDATA */ // Prototypes void printCharToACIA(unsigned char); void printStringToACIA(const char *); void printCharToVDU(unsigned char); void printStringToVDU(const char *); void waitUART(unsigned int waitTime); void wait_Until_SD_CMD_Done(void); void write_SD_LBA(unsigned long); void readSDBlockToBuffer(void); void wait_Until_SD_Char_RD_Rdy(void); int main(void) { asm("move.l #0x1000,%sp"); // Set up initial stack pointer printStringToVDU("Waiting on SD Card ready\n\r"); wait_Until_SD_CMD_Done(); printStringToVDU("SD Card is ready\n\r"); printStringToVDU("Writing LBA = 0\n\r"); write_SD_LBA(0); printStringToVDU("Reading block\n\r"); readSDBlockToBuffer(); printStringToVDU("Block was read to 0xE000\n\r"); asm("move.b #228,%d7\n\t" "trap #14"); return(0); } void readSDBlockToBuffer(void) { unsigned short loopCount = 512; unsigned char readSDChar; unsigned char * destAddr; destAddr = (unsigned long) BUFFER_START; * SD_CMD_REG = SD_RD_BLK; while (loopCount > 0) { wait_Until_SD_Char_RD_Rdy(); readSDChar = *SD_SDDATA_REG; *destAddr++ = readSDChar; loopCount--; } } void write_SD_LBA(unsigned long lba) { unsigned char lba0, lba1, lba2; lba0 = lba & 0xff; lba1 = (lba >> 8) & 0xff; lba2 = (lba >> 16) & 0xff; * SD_LBA0_REG = lba0; * SD_LBA1_REG = lba1; * SD_LBA2_REG = lba2; } void wait_Until_SD_Char_RD_Rdy(void) { unsigned char charStat; charStat = * SD_STATUS_REG; while (charStat != 0xE0) { charStat = *SD_STATUS_REG; } } void wait_Until_SD_CMD_Done(void) { unsigned char charStat; charStat = * SD_STATUS_REG; while (charStat != 0x80) { charStat = *SD_STATUS_REG; } } void waitUART(unsigned int waitTime) { volatile unsigned int timeCount = 0; for (timeCount = 0; timeCount < waitTime; timeCount++); } void printCharToACIA(unsigned char charToPrint) { while ((*ACIASTAT & ACIA_TXRDYBIT) != ACIA_TXRDYBIT); * ACIADATA = charToPrint; } void printStringToACIA(const char * strToPrint) { int strOff = 0; while(strToPrint[strOff] != 0) printCharToACIA(strToPrint[strOff++]); } void printCharToVDU(unsigned char charToPrint) { while ((*VDUSTAT & ACIA_TXRDYBIT) != ACIA_TXRDYBIT); * VDUDATA = charToPrint; } void printStringToVDU(const char * strToPrint) { int strOff = 0; while(strToPrint[strOff] != 0) printCharToVDU(strToPrint[strOff++]); }
Results
Reading 6809 FLEX SD Card.
TUTOR 1.3 > GO 2000 PHYSICAL ADDRESS=00002000 Waiting on SD Card ready SD Card is ready Writing LBA = 0 Reading block Block was read to 0xE000 TUTOR 1.3 > WHAT TUTOR 1.3 > MD E000 00E000 00 41 49 4E 00 00 00 00 42 4F 4F 54 47 45 4E 00 .AIN....BOOTGEN. TUTOR 1.3 > 00E010 45 58 45 00 24 00 00 F0 00 00 00 00 00 00 00 00 EXE.$..p........ 00E020 53 59 53 54 45 4D 00 00 48 45 4C 50 00 00 00 00 SYSTEM..HELP.... 00E030 45 58 45 00 25 B7 00 F0 00 00 00 00 00 00 00 00 EXE.%7.p........ 00E040 48 45 4C 50 00 00 00 00 53 59 53 54 45 4D 00 00 HELP....SYSTEM.. 00E050 48 4C 50 00 27 20 00 F0 00 00 00 00 00 00 00 00 HLP.' .p........ 00E060 53 59 53 54 45 4D 00 00 43 4F 50 59 00 00 00 00 SYSTEM..COPY.... 00E070 45 58 45 00 29 00 00 F0 00 00 00 00 00 00 00 00 EXE.)..p........ 00E080 53 59 53 54 45 4D 00 00 44 49 52 00 00 00 00 00 SYSTEM..DIR..... 00E090 45 58 45 00 2B 00 00 F0 00 00 00 00 00 00 00 00 EXE.+..p........ 00E0A0 53 59 53 54 45 4D 00 00 43 48 4B 44 49 53 4B 00 SYSTEM..CHKDISK. 00E0B0 45 58 45 00 2D 00 00 F0 00 00 00 00 00 00 00 00 EXE.-..p........ 00E0C0 53 59 53 54 45 4D 00 00 41 53 4D 00 00 00 00 00 SYSTEM..ASM..... 00E0D0 45 58 45 00 65 00 00 F0 00 00 00 00 00 00 00 00 EXE.e..p........ 00E0E0 53 59 53 54 45 4D 00 00 41 53 50 00 00 00 00 00 SYSTEM..ASP..... 00E0F0 45 58 45 00 6E 00 00 F0 00 00 00 00 00 00 00 00 EXE.n..p........ 00E100 53 59 53 54 45 4D 00 00 42 41 53 49 43 00 00 00 SYSTEM..BASIC... TUTOR 1.3 >
Works well!
-
Fixing Handshakes
02/21/2022 at 12:04 • 0 commentsTried loading from the serial port and had issues again.
Found the problem is related to the inability of the n_rts line to respond early enough to slow the USB (FPGA to Host) handshake in time. The bufferedUART.vhd code was set to turn off RTS when there are > 8 chars in the receive buffer. The FT230X part doesn't react that fast. Changing the threshold to 4 fixed the problem.
-- RTS with hysteresis -- enable flow if less than 2 characters in buffer -- stop flow if greater that 4 chars in buffer (to allow 12 byte overflow) -- USB-Serial is fast, but not fast enough to make this larger process (clk) begin if rising_edge(clk) then if rxBuffCount<2 then n_rts <= '0'; end if; if rxBuffCount>4 then n_rts <= '1'; end if; end if; end process;
I can now download code again.
Download Code Procedure
- Run puTTY on the Serial port
- puTTY conflicts with the USB Blaster so it has to be shut down
- puTTY should be set to no add LF or CR
- Assuming the file already has CR LF on each line
- Can check by puTTY settings, Terminal Implicit LF or CR turned off
- Open the download file in a text editor
- I like notepad++
- Make sure the last line in the file to download is
- S9032000DC
- If it's not, add the S9 line with a CR at the end of the line
- Select all, copy to copy-paste buffer (CTRL-C)
- Type LO2 on the VDU keyboard.
- On the Serial port, insert the text with CTRL-V
- After the download, TUTOR will return to the prompt
- Ready to run the program
- GO addr
- Run puTTY on the Serial port
-
SDRAM Working in a Different Context
09/05/2020 at 12:28 • 0 commentsThere's an interesting project from 2014 called TG68 Experiments at Retro Ramblings (AMR) to create a 68000 CPU that uses the SDRAM on these inexpensive FPGA cards. The project starts with the 68K same core (TG68) I've been using by Tobias Gubener and builds on it. It improves on the TG68 SDRAM design considerably. Here's the GitHub repository for the project.
This project has quite a few appealing features including a large frame buffer and the ability to load code from an SD Card. AMR has spent quite a bit of time building a fast SDRAM interface including a 2-way associative cache. He also does pixel dithering which I used to map the 16 bit graphics to the 6-bits of the RETRO-EP4CE15 card.
It took a solid day of fumbling around to port it to my RETRO-EP4CE15 card with a Cyclone V FPGA card but it's now running. In the end I routed some of the obvious lines (resets. clocks) out to the FPGA's extra I/O pins and used my logic analyzer and scope to debug the problems. The project is pretty well documented but the following are my notes from the port.
Here's a picture of the screen on a VGA monitor.
Fits in Cyclone V FPGA
There's plenty of room on the Cyclone V FPGA. It should fit in a smaller FPGA just fine.
Started with Cyclone III Example
AMR chose a cheap Cyclone III card from flea bay. I chose to port the Cyclone III example thinking it might be closer to my Cyclone V FPGA card than the other board examples. That might not be the case, but it is what I did. The other boards had a lot more LEDs, switches, etc. The Cyclone III card had minimal resources.
The card had two SDRAMs so it took some effort to remove support for the second SDRAM. In fact, that was the last domino to fall since I still had VHDL fragments from the 2nd PLL which I had only partially removed so it was causing the 68K to stay in reset.
Serial Port Message
On the way to booting, this status message was printed to the serial port (at 115,200 baud) (several reboots shown below):
SD Card Contents
AMR's TG68 Experiments needs an SD card with some specific contents, namely an S-Record file with the boot code. AMR bootstraps directly from the SD card so the bootstrap code needs to be in the root folder with a specific file name.
If you want to try it out, just copy the file CFirmware/out.srec to the root of the SD card, and rename it to “boot.sre”.
That seems to be working since I see a window on the VGA screen with S-Records.
Here's one of the s-records from the VGA screen compared to the out.srec file contents. Not sure why there's less lines in the window but the one line does look right.
I wonder if this shouldn't be different code, namely the sdbootstrap.srec file.
I tried a few different sre files and they seemed to all work.
Replaced the PLL with a Cyclone V PLL
Quartus seems finicky with upgrading the PLL so I re-generated another one. The outputs are 100 MHz, 100 MHz, and 25 MHz in case someone tries to figure it out.
How the Top Looks in Quartus
This view of the hierarchy in Quartus might be helpful:
Building the Code
I copied the code to my Linux Virtual Machine (built earlier). However the code requires vasm which I don't have at the moemnt.
My GitHub Repo
The code for this project is in my Retro-Computers GitHub repository. The VHDL code for the build starts in here.
End of TS2 Series?
This could be the end of this TS2 series. I think I will shift over to getting the TG68 as implemented by AMR working.
Postscript
Rebuilt the EP4CE15 version of the card using the lessons learned from the Cyclone V build including the busstate signals and the External 1MB SRAM. Tested the build and it worked. Here in GitHub.
-
Built demo.c
08/30/2020 at 14:12 • 0 commentsJeff Tranter has a piece of demo code that is written in C. The code prints lines with number of 1 to 11 along with the number squared, the number to the 4th power and the factorial of the number
Makefile Issues
Jeff's Makefile has troubles with my version of the GCC compiler but all I needed to do to fix it was remove the include for the coff file. Doesn't seem to be a problem since obj-copy figures out the file type without it. I had the same issue with building assembly code.
The Makefile has:
all: demo.run demo.s demo.run: demo.c /opt/m68k-elf/bin/m68k-elf-gcc -Wall -m68000 -msoft-float -c demo.c /opt/m68k-elf/bin/m68k-elf-ld --defsym=_start=main -Ttext=0x2000 -Tdata=0x3000 -Tbss=0x4000 --section-start=.rodata=0x5000 demo.o `/opt/m68k-elf/bin/m68k-elf-gcc -m68000 -print-libgcc-file-name` /opt/m68k-elf/bin/m68k-elf-objcopy -O srec a.out demo.run demo.s: demo.c /opt/m68k-elf/bin/m68k-elf-gcc -Wall -nostdlib -nodefaultlibs -m68000 -S demo.c clean: $(RM) a.out demo.o demo.run demo.s
Running the Program
The program starts running at address 0x2000 and does the following:
TUTOR 1.3 > GO 2000 PHYSICAL ADDRESS=00002000 Start n n^2 n^4 n! 1 1 1 1 2 4 8 2 3 9 27 6 4 16 64 24 5 25 125 120 6 36 216 720 7 49 343 5040 8 64 512 40320 9 81 729 362880 10 100 1000 3628800 11 121 1331 39916800 Done TUTOR 1.3 >
Useful Functions in example code
Jeff provides two functions which use the TUTOR monitor for calls:
void outch(const char c); void printString(const char *s);
The code for these programs is:
// Print a character using the TUTOR monitor trap function. void outch(char c) { asm("movem.l %d0/%d1/%a0,-(%sp)\n\t" // Save modified registers "move.b %d0,%d0\n\t" // Put character in D0 "move.b #248,%d7\n\t" // OUTCH trap function code "trap #14\n\t" // Call TUTOR function "movem.l (%sp)+,%d0/%d1/%a0"); // Restore registers } // Print a string. void printString(const char *s) { while (*s != 0) { outch(*s); s++; } }
The outch( ) routine is conveniently written in assembly so it provides a nice example of in-line assembly language code.
Return to TUTOR
main( ) cleanly returns to the Tutor monitor. It does that by using a TRAP:
// Go to the TUTOR monitor using trap 14 function. Does not return. void tutor() { asm("move.b #228,%d7\n\t" "trap #14"); }
The trap 14 handler code in TUTOR header has:
8162 *------------------------------------------------------------------------- 8163 * File TRAP14 Trap 14 handler of "TUTOR" 06/25/82 8164 8165 * CALLING SEQUENCE 8166 * %D7 = XXXXXXFF WHERE "FF" IF FUNCTION NUMBER 8167 * TRAP #14 8168 8169 TRAP14: 8170 be70 48E7 4160 MOVEM.L %D1/%D7/%A1-%A2,-(%A7)
This finally validates the GCC toolchain works.
-
Enhanced BASIC
08/30/2020 at 12:02 • 0 commentsJeff Tranter also ran the Enhanced BASIC on his TS2 build. It loads into ROM on his card from 0xC000-0xCFFF. This card is compatible with Jeff's design (it's based on Jeff's design which is a copy of the Teeside TS2 board so any software that Jeff got running should run on this card.
I added a 16KB internal SRAM to that range and uploaded Enhanced BASIC to the card and it worked.
A short program...
I could change the SRAM into ROM and have BASIC always ready to run.
-
Cleaning up a noisy counter
08/29/2020 at 13:57 • 0 commentsLater note - Went away from this approach...
Using a binary counter for the wait states is not a good idea. The reason is that counters when decoded have noise when they transition. That's because they transition more than one bit at a time.
The classical solution to this problem is to use a grey counter which only changes one bit at a time. It does count strangely when viewed as numbers but it's much easier to decode and it is glitch-free.
Here's a 4 bit grey count:
0000 -> 0001 0001 -> 0011 0011 -> 0010 0010 -> 0110 0110 -> 0111 0111 -> 1111 ...
Here is the logic analyzer capture:
Unfortunately the flakey S record load at 25 MHz happened again. Dropping back to 16.7 MHz fixed it again. Still haven't fixed the edge condition....
Timing to access external SRAM.