Tuesday, 26 October 2021

Nezha : Using syscalls for IO

 It was back in July I first posted about my Nezha RISC-V SBC.  At the time I was pleased to have a solid, reliable Debian build and excited with the ability to write native RV assembly programs and run them  at the command line without the usual inconvenience of cross-compilation and loading.

I purchased Anthony Reis' (AR) beginners guide to RV assembly which provides a gentle learning curve for me.  It starts with a chapter on machine language which is interesting as it describes the format of some types of instructions ().  I am hoping not to do too much low level debugging but this info provides an insight into the RV design, in which instructions are standardised to facilitate their implementation on a variety of hardware platforms.

One of the problems with an instructional RV book is that people have a range of environments in which they write programs.  Many would use a QEMU RV VM, some would have a smaller RV machine to load executables onto and a lucky few like me have an RV linux SBCfor native compilation. As AR starts on the assembly language tutorials he provides his own program which functions as an RV-32 assembler and simulation environment.  This provides input output to the screen using his own bespoke functions.  For example two instructions sin and sout are provided to input / output a string to / from a program.  A lot of assembly programming deals with peripherals so this isn't very helpful (although it is the correct approach for a general purpose tutorial / textbook).

The first thing I need to do is to work out how to implement the same functionality in my linux / gcc environment so that I don't need to use AR's assembler / io functions.  Previously I was able to use Stephen Smith's hello world example which uses a linux system call (ecall) to output a string.  Instead of using ecall it is possible to to the call statement, so that you can use the C function name rather than a numeric syscall number.  RV registers a0, a1, a2, ... registers are used for the parameters.  I was very pleased with my first attempt, shown below, which calls printf to display a string containing an integer parameter.  I needed to link it with a linker option "-no-pie" to include the necessary library modules for terminal output.


Once we have this mechanism it is easy to provide simple macros with the same name and parameter as those used in Anthony Reis book.  Now my first program example, which adds two numbers together looks just like the one in the book.





Sunday, 17 October 2021

DIY Frequency Counter

 

I am concerned with my 6502 reliability now that I have increased the clock speed to 1MHz and I want the ability to slow the clock down (again).  I could revert to my arduino Nano clock but this is quite a bit slower.  Instead I decided to use a decade counter so that I can slow the clock by a factor of 10, 100, 1000 etc.  Chips are ridiculously chep and I can easily add one next to the clock on the breadboard.
It occurred to me that I need to measure my clock speed to be sure the counter is having the expected effect.  It would also be very useful to check the nano clock generated frequenct if I am using it.

Ebay shows some cheap kits alongside expensive "professional" equipment.  I only need a rough idea so a kit is perfect.  It comprises TTH (through the hole) components, 5 x seven segment displays for output and a PIC16 microcontroller for measurement.

The only instruction provided is a link to a youtube video.  It turns out to be very helpful.  Kev, the guy who provides it, makes a board whilst talking, it takes about 5 minutes.  It is reassuring and charming that he is quite amateurish.  There are a couple of important points he makes, firstly how to solder the extra capacitor to improve low frequency measurement and secondly a reference / link to operating instructions he has found.

The board is very nice to solder with well-spaced components and generous solder pads.  I built it and it works.  It accurately tested a 20MHz oscillator as having a frequency 20.064 MHz.  Next I measured the clock speed on my W65C02SXB board, which I understood was running at 8MHz.  The measurement was 1.8MHz, looking at the clock chip on the board I noticed that this is correct - so the tester has already proved itself useful.

In conclusion, I am very pleased with this circuit, it is always nice to solder useful things.  I am now ready to face my next 6502 test.








W65C02SXB : WDC to the rescue

 

I am a little nervous about my 6502 system.  I moved beyound the "use wires to connect hardware on breadboard" stage so time ago and I am more intereseted in software development now.  In fact I am aiming to run C and BASIC programs on my system next.  Underneath the hardware is working but subject to the vagaries of bad connections or deficiencies in programming due to my incomplete understanding.  The recent increase in clock speed (or some undiscovered unknown issue) has led to the system becoming frustrating to work with and almost unuseable.

Whilst considering buying a circuit board to formalise my hardware (for example from dbuchwald) I came across a development board from WDC  which perfectly matches my requirement. It was released in 2014, apparently as an educational board and is still available. WDC have been the main player keeping 6502 hardware ecosystem alive for many years now so a board from them is likely to be good.

The W65C02SXB  has a 65C02, ROM, RAM, VIA and ACIA just like mine.  Obviously it has the advantage that all connections are in place and should be reliable.
The clock runs at 8MHz s the board should be significantly faster than my existing breadboard version.
The second enhancement is that all necessary pins, including data bus address bus and 65C02 control pins are available on headers so are easily accessible for attaching devices / peripherals.

I ordered one immediately from Mouser in the UK and it was delivered by Fedex five days later after an epic journey from Grand Prairie, Texas.



There is a getting started project provided by WDC which demonstrates how to assemble (WDC02AS), link (WDCLN) and run a program to flash the onboard X LEDs.  The program is loaded and run using the debugger (WDCDB) which shows you the assembler source, memory variables / registers and allows you to single step or run through a program.  This is magnificent and provides a whole new world, hopefully making it much easier to develop code.

A second project  providing very detailed instructions is available from Instructables to flash an external LED attached to a VIA pin.  The executable image is loaded via TIDE (Terbium IDE) into memory and can then be run using the debugger.

These WDC tools make software development a very different experience from my DIY environment and hopefully speed up the process.  All I need to do is attach appropriate hardware to the board connectors and start development.  It looks like WDC and instructables hoped for other projects to be based on the board but I haven't seen many, there are a few references on 6502.org which I can follow up.

Monday, 20 September 2021

6502 : Xmodem Fights Back



 Previous I have been pleased to be able to (1) download a file to RAM and (2) use xmodem to transfer a program and then run it. I was very pleased with both results and felt that I had cracked xmodem.  The good feeling didn't last long.

Download speed

I wanted to get started on testing my C programs and they use the terminal working at 19.2k baud whereas my download testing has been conducted at 9600 baud.   The C program displayed some garbled characters when the speed was reduced to 9.6k and in general my programs work at 19.2k so I need to standardise my transfers on 19.2k.

Increase clock speed

Unfortunately, when I changed to 19.2k my xmodem downloads appeared to complete but would not run as they were losing characters.  My thoughts turned to flow control or increasing the clock speed.  RTS/CTS flow control didn't seem to work last time I tried it and I don't really need my Nano slow testing capability so adding the 1MHz clock chip is the way to go.  

Changing over to the clock chip simply requires connecting 5V, GND and the clock output to 6502.  After doing this nothing was displayed on the terminal screen with a simple program which outputs a message.  I find I need to put a 255 cycle delay loop between each character output to the terminal.  I tried RTS/CTS flow control but it made no difference.

A short while later I discovered, on the 6502 site forum that the 65C51 has a design error which means that flow control doesn't work


 The easiest workaround is the method I chose; to insert a delay.

Spurious Interrupts

With the transmission speed fixed, I returned to testing xmodem downloads.  Unfortunately matters became worse.  The 6502 appeared to randomly restart itself during or after downloads.  I guessed that the system was getting interrupts, causing it to jump to the reset vector.  So far I have only covered Ben's interrupt tutorials and haven't set anything up.  The 6502 has an NMI pin (connected to 5V) and an IRQ pin connected to the 6522 VIA CA1 pin.    I set up small code snippets which displayed a message on the terminal when one of the interrupts occurred and configured the NMI and IRQ vectors accordingly.

As expected the IRQ vector was used each time a spurious interrupt occurred.  This happened even when the IRQ pin was held high.  The 6502 provides a BRK instruction (opcode $00) which also causes an interrupt to the IRQ vector.  When an interrupt occurs, the interrupt return address and process status register byte are written to the stack.  Initially my code to test BRK would not return to continue the program when an RTI (return from interrupt) instruction was encountered.  I found in an article that compilers need to treat BRK as a 2 byte opcode to jump back to the correct address but they only reserve 1 byte ($00) which means the program returns to the wrong address.  I corrected this by adding NOP after BRK and RTI then works fine.


I spent some time writing interrupt code which saves the type of interrupt, return address and interrupt count to page zero variables so that I can print out interrupt details.  A separate subroutine can print this information out to the LCD on request.   For debugging spurious interrupts we only need capture a single interrupt so the interrupt processor has an option to print details within the interrupt and not return to the program.

With the capability to determine spurious interrupt details in place we are now more prepared to continue debugging xmodem.




Monday, 30 August 2021

6502 : Xmodem

 My 6502 system is working well but I still find the program upload process irritating.  I am probably being a diva about this as the old school method to remove, program, replace the EEPROM chip was very painful.   My programs are quite small but it takes time to compile them, transfer them to an Arduino sketch then run the sketch to copy the program to EEPROM.  For a 1KB program, which is quite large for my assembler programs but reasonable for C it can take a minute to process.

I have been thinking of trying to implement XMODEM for a while, it seems sensible to use the serial port session which will allow a transfer at 19200 baud, taking a few seconds for program download into RAM (not EEPROM).  6502.org provides a copy of Daryl Rictor's xmodem code so a couple of weeks ago I tried it out.  The code is intended for a 65C02 + ACIA 6551, the same as mine, and it is only a couple of hundred lines long so I thought I have a good chance of success.  I was a little nieve but that is the best way to start a long journey.

It was easy to download the program and tweak it to compile/load successfully.  However, on starting Xmodem nothing happened.  Not knowing the code or the protocol or having a tool to look at serial port traffic meant that debugging and experimentation were unsuccessful.

I found the modem protocol is quite simple so I wrote a C program under Windows WSL to download a test packet meaning that at least I had reasonable input.  I still couldn't get the example code working so I wrote my own version called xm.  After a while this worked fine, I could compile a program, start xm running and run my serial program to send the machine code. I excluded most of the modem error checking, particularly block number and CRC checks as we are transmitting at quite slow speeds down a 15cm cable.  The only downside is that I have to exit Putty to start the serial program downloading as they share the COM port; on completion I have to restart Putty.  This can be accomplished by means of a batch file loop but still it doesn't seem right.

In an effort to streamline this process I considered writing my own terminal emulator, from which I could easily start the transfer program.  Again I chose C under WSL as my development environment.  Configuring and using serial ports with C isn't terribly easy, some low level commands are required to setup the UART; as usual a good tutorial made this easy.  After that READ and WRITE statements can be used to fill/send buffers through the port.  Under Linux and WSL there isn't a function kbhit() to tell you if the user has pressed a key so I had to implement that myself based on Morgan Mcguire.  Although I could easily capture and display information from the 6502 and deal with keyboard input properly I couldn't get the two to work together seamlessly and I didn't complete this attempt.

On a whim I googled to see whether there are any software only (free) packages which can monitor the serial port.  It turns out there are a few, and Serial Port Monitor seemed a good choice.  The free version is old and not Windows 10 friendly so I used a demo of the paid version.  It is a shame it costs $100 so it is't something I would buy for a one-off problem.  The software is clever enough (using admin privilege) to share the serial port with Putty and after a few minutes learning I could see the serial port traffic.

Using Serial Port Monitor I could see that xmodem was sending a good packet to the 6502 but it was being NAKed by the 6502 and repeatedly resent.  My debugging focussed again on the sample code but I still couldn't get it working.  In particular, not all bytes were read in the ACIA port properly.  I tried all sorts of things to make it work, including slowing the transmission to 9600 or 4800, swapping my Arduino Nano controllable clock for the 1Mhz chip,  using RTS / CTS flow control with extra wires on the USBTTL connection, putting delays on the 6502 send characters which were being garbled.

Eventually I decided to write my own 6502 program, jmodem.  With my new understanding of modem and the structure of the sample code it was a simple job to write my own using subroutines I have previously written.  The only new feature is to read characters until no more come.  Xmodem sends a 128 byte buffer with 3 header characters, terminated by two CRC bytes.      It then stops and waits for ACK or NAK.  If any characters are lost there will be less than 133 characters in total.  Once I had this subroutine working with Putty terminal input remaining coding was easy.  The program initially accepted just one block, checked the number of bytes and transferred it to a fixed memory address.  It was then easy to loop round until an EOT byte was received.


Success is sweet.  I can now load programs into RAM quickly when I want to without exiting Putty using a standard technique.  Completed programs or subroutines can still be saved in ROM using the Arduino Mega but we no longer need it for normal development or system usage.





Thursday, 19 August 2021

Printing reports from Google in Landscape

I have a simple but very useful mariadb/mysql database for my art slideshow app and I use the excellent utility HeidiSQL to maintain it.  Mariadb doesn't have reporting capabilities which is a problem for me as I occasionally need to print lists of pictures.  It is, of course, possible to create and display queries and I can save these to a linux file.  However they need some formatting and importing them to Word, setting up the layout, checking it looks ok is a pain.  Exporting csv data and reading into Excel is a comon way of processing records, but I am not keen on writing Excel macros to do this.  I am sure there are lots of reporting packages I could use but that would be overkill.

I do have the capability to output a selection of records to a browser thanks to Tania Rascia's excellent tutorial.  I use the web query to update descriptions in the database associated with pictures so I thought it would be worthwhile to see whether I am able to print reports.  Usually printing from a web browser provides what you want but is messy due to screen formats being inappropriate but I thought some tailoring would be possible.

In fact it turns out to be a simple and effective solution.  Clearly we want to use CSS to reformat our web page for printing.  Using the @media CSS rule you can specify separate definitions for screen and print.  My first experiment was to display screen text as blue and printed text as green.
To test output just choose print in the browser and you see the print version of the report in print preview


After that we can write print specific CSS to ensure the report is in landscape mode and that instructions and unnecessary screen text are hidden.  I can also set up a print button on my screen.


A very satisfying solution to my problem.






Wednesday, 11 August 2021

Windows 10 Pro

Why

One of the good things about using RPis is that we can SSH into them remotely so it is easy to use multiple systems for different purposes with a single screen (or two) and keyboard.

I am planning to purchase a new PC but I am not looking forward to it  because of all the tasks involved in switching over from the old one.  It would be much simpler and satisfying to run old and new in parallel.  I could set up the new PC and transfer over important and frequently used applications and data.  There are lots of apps, data, configurations on the old one which I probably don't need and I could leave them in place initially.

Unfortunately running two Windows PCs with separate screens and keyboards is a pain.  They take up a lot of space and aren't convenient to use.  I could use KVM style screen / keyboard switch but good ones are expensive and I find them messy.

I could use TeamViewer, splash top  or VNC to access the old PC from the new one.  In the past I have found them a bit clunky but that is probably my lack of familiarity.  However I decided to try Microsoft Windows Remote Desktop which I would hope is well integrated.

How

To use RDP I need my existing Win10 PC to be running Win10 Pro.  Win10 Pro doesn't have many useful features but RDP and bit locker disk encryption are good.  

Buying direct from Microsoft is quite expensive but a quick Google showed me that there are plenty of third-party suppliers who can provide a product key for about £20.  These sites can be dodgy so I picked one called unitysoft, which has an office address and support available.  On purchase I received a product key and some straightforward instructions.

All you really have to do is change the product key in Settings > System >  About.
The computer then spends a couple of minutes reconfiguring existing software so you have Windows 10 Pro.  You can check this in Settings > System > About 😀😊😊

To access the PC remotely just download the Microsoft Remote Desktop app onto Macbook, iPad etc and connect to the system with your current userid and password.  If you are logged on locally you will be logged off.

So

This is wonderful, just what I always wanted.  I can install my new PC, transfer over what I want to it and leave the old box in the corner connected to network but without screen / keyboard.  If there is something I need over the next few months (and there will be) I can turn on the old PC and sort it out.

In the example below you see my lovely Macbook M1 with a Windows Remote Desktop.  Normally I would run it as a full screen, but this shows the Apple background and apps as well as the Windows desktop.  At the moment I am debugging a 6502 program with my board attached to the PC using a COM port.  I can sit in comfort with no cables or hardware attached attached to my Macbook and happily use Windows functions. Bliss.



Monday, 9 August 2021

6502: Download programs to RAM

 My current mechanism for loading programs onto 6502 is to use the Arduino Mega to download machine code to ROM.  Although this is a vast improvement on using an Eeprom programmer it is quite slow, particularly for C programs which tend to be larger.

It would be preferable to use the 6502 serial interface to download a compiled program to RAM where it cn be executed.  This is analagous to loading a program from disk into memory and running it.  I still expect to save completed programs and subroutines in ROM, but this scheme should make the development cycle easier.

Both Extraputty and TeraTerm provide xmodem transfers.  Daryl Rictor has provided a sample xmodem implementation for 6502 so I have the basic ingredients available to me.

My objective is to take a machine code / hex program from the PC, transmit via USB serial port to the ACIA 6551 then read it in to RAM where it can be executed.

Initial tests did not go well. I dont have the ability to log the character string that Extraputty / xmodem is sending or an understanding of the protocol or much idea of how the receive program works.  The trial and error method is somewhat doomed.

The xmodem protocol is intended to be simple to implement, a major factor in its long term popularity. 

 
Data is downloaded in 128-byte packets.
Each packet has a 3 byte header: <soh=0x01> <block number> <inverted block number>
There is also a 2 byte trailer containing a CRC code.
This makes a total of 133 bytes

The receiver sends a character 'C' to the sender to start transmission.
Sender responds with a packet (133 bytes) which the receiver acknowledges with <ACK>.
The receiver carries out block number and CRC checks, if they fail the receiver sends <NAK> instead of <ACK> and the sender retransmits.
This is repeated until all packets are sent, at which point the sender sends <EOT=0x04>

To simplify testing I wrote a C program on my PC which sens a single xmodem format packet to the 6502.  I was pleased to find that Windows/WSL allows me to use a PC COMnn port as /dev/ttySnn providing the program has sudo privileges.  It is a bit fiddly to configure the settings but straightforward if you have a good tutorial .  The completed program looks more complicated than it is. 

Unfortunately, even with a known test program I couldn't make xmodem work. My 6551 works fine but my system or ExtraPutty may be incompatible in some way with Daryl's xmodem example.

I then decided to write my own xmodem receiver.  I simply have to read in some data packets, in a known format, into RAM using my existing subroutine library and I have Daryl's example for hints and guidance.  As we are using a short local connection I can skip the error checking - if an error occurs I would just reload the program.

This approach is much more successful.  I can take an executable program, created using cc65 on the PC and transfer it to 6502 RAM.  After checking using the monitor that my first program was transferred successfully to RAM address $1000 I tried to run it but (of course!) it failed.  The program had originally been compiled to run at $8000.  Once I changed the .org statement to rectify this it ran fine.  I would include an  image but the test program just displays a '#' character and allows character input.

This is an excellent result.  Although there are currently a number of rough edges to smooth over we have a working solution.  It allows us to reduce reliance on the Arduino Mega and the expectation is that it will accelerate downloads and speed up my development cycle (which involves frequent program changes).

Wednesday, 21 July 2021

Nezha : creating an image

Debian 0.3 Image

I received a working Debian Image with my Nezha, which is great but its only provenance was that it came with the board and was built on 1st June, just before the boards were shipped.  On 10th June Wu Caesar, the main man, provided an "official" release Debian 0.3 which was built on 3rd June.

I struggled to burn it to an SD card as it wasn't in a standard image format.  The Telegram forum was vital to resolve this.  The readme.txt said that you need a utility "PhoenixSuit"  used by Allwinner to burn the image.  However, try as I might, I couldn't get PhoenixSuit 3.1.0 to work.  A Telegram post on 1st July provided a link to RVboards downloads; the RVboards SBC is identical to the Nezha.  The download site contained PhoenixCard 4.2.5 which is a much newer version of the image burning software.  I successfully burned Debian 0.3 images to both 64GB and 16GB SDcards.  After using PhoenixCard you can't reformat SD cards using Windows but it may be possible to fix with the PhoenixCard "restore" option.

The image has networking configured and boots into an LXDE GUI on the HDMI port.  Although slower than other Linux SBCs it was great to see it is a proper product.  GCC is ready for use so we are off to a great start.  In the following minor setup tasks I was most pleased that configuration activities were totally normal.

Debian 0.3 configuration

I want to run the system headless, so I set up a static address.  Systemd networking is used so there was a slightly different procedure, setting up a file /etc/systemd/network/lan0.network containing the static address details.  Once the static address is in place I can use SSH access and copy over an ssh-id file for autologin.

At first I wasn't sure if / how the console is configured as we dont have a boot config.txt file.  The board comes with a USBTTL cable and I found details for connections in the advert for the rvboard on AliExpress!  Once the serial cable is connected and started at 19200 baud we see the console startup which has much useful detail in it.

I could now change the run level using systemctl from graphical.target to multi-user.target.  Startup and shutdown are now significantly faster.

Debian 0.5 image

On 2nd July Pierce Andjelkovic kindly provided a Debian 0.5 image on Telegram.  Again I had a tortuous trial and error experience installing it. The instructions are in Chinese but Google translate does a great job in decoding the chinese character sequences.

The image is copied to an SD card using dd then adjusted using gdisk to delete the 6th and last partition.  I struggled to get gdisk to delete the partition on my 16GB disk and eventually found I could do it using my Nezha board, running Debian 0.3.  I also found that simply burning the image to a 32GB SD card is a lot easier, it doesn't need the partition to be deleted.

The same configuration tasks were completed for static IP (although I needed to edit the traditional /etc/network/interfaces) and runlevel.

Debian 0.5 software

I could use apt-get to upgrade software successfully and installed lighttpd as a simple webserver without difficulty.  This is great, we can assume that the usual debian functions work normally.

I wanted to use a samba client to access shares on other systems but cifs is apparently not included so I could not mount devices on other systems.  However I could install samba and configure local shares so that other systems can copy files on/off.

Having GCC native compilation available is wonderful so I quickly tested the hello world C program.  More importantly and exciting is that I can do native compilation of risc-v assembly programs.  Not knowing what risc-v instructions are or how to program isn't a problem.  With Google as my friend I was able to successfully compile and run a risc-v hello world program, amazing 😁

To learn assembly I purchased a book RISC-V Assembly Language by Anthony Dos Reis which was mentioned on Telegram forum.  It appears to provive a nice simple introduction so I am looking forward to it.

Wednesday, 23 June 2021

Nezha : RISC-V Linux SBC

The title of this post contains ample details to excite (me).  The "open source" architecture RISC-V is well on its way into the mainstream.  To be of general interest it needs to run Linux and a price point of $99 is well below previous development boards.

I ordered one as soon as I saw the indiegogo crowd funding page on 21st May.  Crowd funding was complete by 26th May, boards were shipped about 8th June and mine arrived yesterday.

Nehza has a similar form factor to a Raspberry PI and similar connectivity for HDMI, power, Ethernet, Wifi, Bluetooth, USB and Audio.  In a direct comparison RPI4 is faster, with more capabilities but that isn't the point.  Here we are running RISC-V not ARM.  Personally I feel this is an important moment in the evolution of systems.


I connected up the board, inserted the SD card provided and booted it up.  It started a Debian desktop and allowed me to signon.  Once ethernet was connected, I could happily SSH into the system.  This is perfectly what I hoped for.  I have a new (but familiar) world to explore.

Friday, 18 June 2021

6502 : CC65 and C Programming

Until now I have used VASM to assemble my 6502 programs and it has done the job well.  I have noticed that there are a few 6502 C compilers and I recall from my bare metal programming that you (only!) need a stack, a library and some initialisation code for a C environment.  There appears to be a WDC compiler which isn't well used and CC65 which is popular and practical.  As a first step I will move from using VASM assembly to CA65, which is a part of the CC65 program suite.

CA65

As CC65 is available as a debian package and I use Windows 10 for my 6502 development environment I installed it under WSL (Windows Subsystem for Linux).  I can now take assembler source programs, which are written in Notepad++ and copy the to directories I use for WSL.  Assembly with CA65 starts with running ca65 at the command line with a few options specified.  In particular we have to specify --type as "none"; CA65 is happy to assemble for various microcomputers (C64, Apple ][, etc) but my home brew system has no extra requirements.  The output listing shows that it creates the same output byte for byte as VASM.  The output file is formatted for linking modules and libraries so although I have nothing to link in I also need to run the linker LD65.  So I replace my vasm command with:
    ca65 -l map -t none testbed.s    and
    ld65 -o testbed.exe -t none testbed.o
Now I can process and load the program via the Arduino Mega as previously.

CC65

Creating a C environment is somewhat more challenging.  Luckily Dirk Grappendorf has set this up for his 6502 which is very similar to mine and has been kind enough to create a github repo containing the code.  I downloaded the repo and set about making my own minimal code base.  My target is a "hello, world" program which outputs a screen message.


There are very few files in the solution:

cc65.lib is the most significant, it is the library of C functions needed for stdio and stdlib.

firmware.cfg defines the different areas of memory in the computer, ROM, RAM layout is specified so the compiler can do the hard work in placing files.

startup.s is the initialisation code which sets up the stack, initialises memory and calls main().

zeropage.s provides the layout for variables in the zero page.

acia.s contains the serial programs init, getc, gets, putc, puts which we will use for screen output.

interrupt.s contains skeleton interrupt processing code (which I am not yet using)

io.inc65 defines a long list of constants for ACIA, VIA and other devices.

Once I edited firmware.cfg for my memory configuration, io.inc65 for my acia addresses and acia.s for my serial port config (19200 baud) I could compile and link the program with a single command:
   cl65 -C firmware.cfg -m firmware.map -o main.exe main.c acia.s zeropage.s startup.s  interrupt.s cc65.lib

This created a 32KB file which can be burned into my ROM.  In fact I use my Arduino Mega to write ROM so I don't want the entire 32KB file.  My program is less than 1KB in size.  I amended firmware.cfg to "pretend" I only had 2KB ROM, which created a much more manageable file.  Amazingly, thanks mainly to Dirk, my C environment works and without too much trouble I can read and write the screen, here is the first test program. 😊😊😊😊😊


C lib

So far we haven't used any C library functions, our example uses Dirks acia_init,acia_getc, and acia_putc for IO.  In fact I can remove include statments for <stdio.h> and <stdlib.h> without issue.  Of course C programs without library functions are not particularly useful, we really want to have them available to us.  I tried adding the abs() function from stdlib.h and it worked fine.  I also successfully tested strcpy() from <string.h>.  

<stdio.h> is more difficult to test; I haven't "linked" my I/O routines into C streams yet and my hardware/software doesn't have interrupts setup so I wouldn't expect I/O to work.  I did hope that I could use the sprintf() function to format output for me and wrote a test program but it didn't work.  I will look into the problem in more detail when I consider cc65.lib.  In fact cc65.lib was provided by Dirk I need to look at how he created it or derived it from cc65 provided libraries.

My mechanism for loading programs into ROM  using an Arduino Mega sketch is wonderful, it is automated and requires no removal/insertion of chips.  Using C and library functions necessarily means that our programs are increasing in size - programs may be 4KB or even more!  The Arduino environment only has 8KB for variables so I had to use the PROGMEM mechanism which directs the compiler to store nominated constants in ROM only.  A 4KB program takes over a minute to load which is not bad really but I will need to look at speeding up the sketch.

SIM65

CC65 also contains a simulator SIM65, which you can use to test your C programs. It is easiest to use with programs containing standard C library functions (printf etc).  You can add in assembly language subroutines from C.

Of course, without the real hardware, low level "driver" functions don't have much meaning but you can "simulate" them.  For example my "term_puts" assembly routine could be replace by one which calls printf.
In fact most or all emulators have this problem, they can't exactly replicate my hardware.  If I aim to design my hardware / software to be similar to Apple ][, BBC Micro, C64 etc I could use their full emulators to test programs but even then my hardware will be quite different from the original product.

I am not sure if I will use this but it is another great tool to have available.



Tuesday, 8 June 2021

6502 : Screen and Keyboard

 

I am thinking that the 6502 should have its own screen.  Traditionally an RS232 serial monitor would be appropriate for the time.  Back in the day I used a VT100 (text) and Tektronix 4025 (graphics) terminal attached to a PDP11 minicomputer.  I did consider buying a small terminal but, unsurprisingly, they aren’t made anymore.


I have an ESP32 and Waveshare 3.5” LCD screen which could be used.  Commands sent to the ESP32 could then be interpreted and the results displayed on the LCD screen.  Graphics would be done by commands as they were on Tektronix graphics terminals.  This is not similar to home computers which used memory map graphics.   ESP32 may be able to do cycle stealing graphics where it interleaves display and 6502 operations.  This would be aligned to the home computer ethos but quite a complex project.

I then considered how an RPI could be used.  Instead of connecting 6502 serial to the PC running putty we could connect it to my RPI 2B (called PI2)  which has a 3.5” screen attached.  I wasn’t sure how to connect my FTDI cable to the RPI.  I connected up with a loopback wire between RX and TX and then set about working out how to use it. 

Using a normal ssh session on PI2 I tried a utility miniterm (which seems to be python but works for me at the RPI command line) and it gave me a choice of ttyASM0 (console) and ttyUSB0  (serial port).  dmesg also shows ttyUSB0 being attached when I plug in the FTDI.  With miniterm using the serial port characters typed at the keyboard were echoed via the loopback wire.  I then setup miniterm to access the 6502 (miniterm /dev/ttyUSB0 -s 19200.  Rebooting the 6502 shows me output in the miniterm session.

PI2 has a Waveshare 3.5” screen directly connected to GPIO pins.  At installation the screen is configured so it is a console.  When PI2, which runs headless, is turned on boot messages are displayed.  On completion there is an autologin to user pi.  Connecting a USB keyboard to PI2 allows keyboard input at the console.  If I start miniterm at the console I see 6502 output on the LCD screen and can enter commands as 6502 input on the keyboard.  JOB DONE!

This is a brilliant solution, for a few minutes work we have a small self-contained text screen and keyboard for our 6502 system.  Purists will rightly argue that it is a modern powerful SoC acting as a dumb screen for a primitive system.  However a modern dumb terminal would be more expensive and have many components.  An old terminal would be real retro hardware, but we aren’t in that business.

miniterm doesn’t have many features and doesn’t support ANSI escape codes well.  I  tried minicom and putty but they didn’t work well for me but I settled on the linux utility screen which is simple but effective.

I can visit the screen topic later to see whether I can find a bit-map graphics terminal solution but for now I am happy with the system.

Monday, 7 June 2021

6502 : Program Library

ROMLIB4

Our subroutine library ROMLIB3 is saved in memory at $E000.  There is nothing special about the code, we could store programs, program snippets or data in the library.  In fact I decided to store programs in ROMLIB4 starting at $E400.

As a first example I stored echo.s, my previous simple command line in ROMLIB4.  Following Dirk Grappendorfs monitor I added a command "jhhhh" to allow the user to jump in to a program.  For the first example "je400" causes the echo program to be invoked with its simple command line.  I added an "e" option to echo which exits back to cmdline with a "jmp $8000" causing it to reinitialise.

Previously I have written two diagnostic programs to show messages on terminal and LCD without using RAM.  I added these to the program library so they can be started from the monitor.  Alternatively they can be started by changing the contents of the reset vector at FFFC, FFFD or writing a short program, loaded at $8000 with a statment "jmp $E4xx".

As with the subroutine library I need to be very careful that labels are unique.  For programs there is more likely to be a clash as one program is often used as the basis for the next.  To make life simple I add a suffix, 1,2,3,4,... to the labels in successive programs to make them unique.

Instead of jumping to a program address from the monitor we would like to do a jump subroutine to an address in the subroutine libary with a call "shhhh", for example "sE1E2" to display registers and return to the monitor.  The "j" jump option used the "jmp (indirect)" opcode but the 6502 / 65C02 doesnt have a "jsr (indirect)" opcode.  I simulate this by putting a return address on the stack and jumping to the subroutine as shown below.

TESTBED

I can now add my cmdline.s to the program library (its start address is $E5D7).  I start a new program testbed.s which starts with the instruction "jmp $E5D7" which is a 3 byte opcode at $8000.  The program itself continues at $8003 and in fact I display "#" as a terminal prompt followed by options which I want to test.  One of the options is "e" which takes us back to the monitor.

Now when I compile and load the program I see my cmdline monitor.  I can then issue the command "j8003" which takes me to the "#" prompt and allows me to run functions I am testing.  Typing "e" takes me back to the monitor.

The testbed program is only about 100 bytes so it assembles really quickly.  The program logic is in ROMLIB4/cmdline.s and subroutines are in romlib3.  This gives me an excellent testing environment.







6502 : Reliability and diagnostic information

Reliability

Our environment for developing and running 6502 programs is still not reliable.  Since I put the hardware on a stand, physical connectivity has not been a problem.  I am past the stage where single stepping through 6502 programs looking at bus signals using the Arduino Mega is regularly required.  However when I turn the 6502 on, or reboot, the system doesn't always come up properly.

When you start the system  the Mega runs its program which typically stop the 6502 whilst it loads a program into ROM.  It is possible to use an external 5V power supply instead and disconnect both 5v and GND from Mega to breadboard.  This avoids any complications due to the Mega doing unexpected things.  It may be necessary to do a reset for the 6502 to boot normally.

I start a new terminal-based "monitor program called cmdline which has options for checking various system information.  Initially I set up power up self test (POST) subroutines for terminal and LCD but there isn't much testing the 6502 can do at start up without using terminal or LCD for output.  On the basis it is obvious if LCD and terminal are working I dispensed with POST.

cmdline has an "r" option which jumps to $8000 to reboot and initialise the system.  Interestingly this is very dependable, implying that startup problems are power or hardware related and the software is working just fine.

Diagnostic subroutines

Option "d" calls a subroutine to display register values: Accumulator, X, Y, P (status flags), S (stack pointer) and PC (Program Counter).  Program status flags are made available by pushing them on the stacvk (php) and popping them (pla) to the accumulator.  The TSX command provides access to the stack pointer.  The program counter is actually available st compile time and is retrieved by loading a label value.

The term-register subroutine is not very useful at the command line as it just shows values when the 6502 is at the monitor prompt; it is more helpful as a subroutine call when testing a program to print out register values.

Dirk Grappendorf has a monitor program which allows the user to display a range of memory addresses.  It is very useful for looking at page zero ($0000), stack ($0100) and working storage ($0200).  We implement "mhhhh" where "hhhh" is the start address to list.  It is pleasing that we can copy Dirks assembly code to convert hex numbers into our program - I don't want to have to write all the code myself.

I was also able to copy another subroutine PRIMM, courtesy of Lee Davidson at 6502.org.  This allows you to put display text in your program immediately after a subroutine call, which avoids situations where the text and code become separated when copying program snippets around.

One issue we face when using the 6502 system is that we dont know what program is running.  To improve the situation we display the program name and assembly time on the LCD and provide an option to display it on the terminal.
We capture the information  to be added within the formatHexProgram and forward variables which are copied into the writeROM sketch.  The sketch loads the information at $FFE0-$FFF7 in ROM so that subroutines can show details on screen or LCD.



Sunday, 6 June 2021

6502 : Library and Shell User Interface

Library

We now have a number of subroutines for simple tasks which will be useful in a variety of programs.  It doesn't make sense to process them every time a program is assembled.  It is much better to save them permanently in an area of ROM, that is to say a library.

We start with a modified assembly procedure which saves object code starting at address $E000.  The library source is a set of subroutines (in alphabetic order) which I call ROMLIB3 (because it was my third attempt!).  Once these have been assembled and saved in ROM we look at the assembly listing to find the start address of each subroutine and add the address as a symbol in our program.  By convention I make the symbols upper case.  I can then delete the source subroutine from the program and replace the jump subroutine name with a symbol.


In this way we can use any or all subroutines in the library simply by adding a symbol table containing start addresses to a program. 

The upload sketch to store hex in ROM can only process about 30-50 bytes per second.  Our programs were increasing in size towards 1KB and we are now down to about 400 bytes so load time is halved to about 10s.

Initial library contents include:
Terminal i/o: getc, init, putc, putstr, hex_digit, hex_digits, registers (to show current contents)
LCD output: init_VIA, init_LCD,  clear, instruction (control command), putc, wait (until ready), hex_digit, hex_digits, putstr

We do have to be careful with our organisation when using libraries.  It is not permissable to change the contents of a library member as this will mean that the start addresses of all subsquent subroutines change and in turn the symbol table in each program needs to be amended and the program re-assembed.  Instead, if a subroutine must be altered, its labels are all prefixed with "OLD" and the new version of the subroutine added to the bottom of the list.  The latest program can then use the new version whilst previous projects remain unchanged.  

Shell

Rather than load a program which executes a single function it is useful to have a "monitor" program.  In fact this is a simple "shell" program such as bash, which is loaded when the user signs on and allows them to carry out various function.

Our shell starts of simple as shown in the picture below.  It shows a title on the terminal, in this case "Ava go" and a ">" prompt.  User input is a single letter, valid choices are l,n,o,p and Return.  The "l" option simply prints an upper case "L".  I find this very useful to check if input is working. "n" displays a hex string on the LCD screen, "o" is a memory dump progrm (wip), "p" tests the newline and "Return" shows a prompt.

We have now moved on from building hardware and writing programs which utilise it to a computer with a user interface and subroutines available to make the programmers life easier.

In the next episode we will expand our shell program to help us check on the current status of the computer.




Wednesday, 21 April 2021

6502: Progress on many fronts

 In the three weeks since my last 6502 blog I have been busy both with hardware improvements and software development.  On the hardware front, a more useful clock has been added, an LED and four buttons have been added to reflect Ben Eaters finished 6502 system and the LCD has been put on the board.  I have also developed a rudimentary hardware error diagnosis procedure.
I have enhanced the vasm/sketch/batch file so a single click can compile and download a new 6502 program and provided some subroutines to write to the screen and use the LED.
These are described in a little detail below.

Subroutines

So far we only have a couple of 6502 assembly programs: one that writes to the screen then accepts input and the other which writes an LCD message.  Assembler is a pain to write so we put everything into subroutines which we can easily re-use in other programs.  In due course we will put the most commonly used into ROM as library routines.  We can immediately add some subroutines based on code we already have:

  init_acia  setup the terminal for i/o   
  putc        write a character to the the terminal
  getc        read a chacter from the terminal
  putstr      write a string to the terminal

Simplified compilation

Previously (see 6502:serial console:software) I simplified my code development cycle to two steps: (1) compile a program and format the executable as input to a sketch; (2) upload the sketch.  Although this beats the pants off removing and replacing an EEPROM all the time it is still tedious.

I found that you can actually use many Arduino IDE functions from the command line using arduino-cli.  I installed it in a folder next to my assembler and tinkered with its configuration file (arduino-cli.yaml) to locate files in line with with my IDE (which uses the portable scheme).  My hardware wasn't recognised automatically in the Windows environment and I had to search a bit to work out that the required platform is arduino:avr:mega.

Once files are in the right place and a batch file links the commands together it is very easy to compile an assembly program and upload the executable in a sketch as a single operation.  This makes software development a lot easier as I forget about the environment and click on a compile icon to build and load a new program version.

I also arranged to save compiled sketches, including executables, as HEX files in the program folder so that I can easily load and run one using a batch file.  I have a batch file for each commonly used program so I can switch between programs easily.

TikTokClk

Ben's 555 clock is a very good learning project but I find it cumbersome in practice.  I set up an Arduino nano to provide a clock pulse on a GPIO output.  Initially I used the serial monitor and delayMicrosecond() function to control the output speed or single step mode.

Once this was working I made it much more useable by adding two buttons to the nano.  One button is used for single stepping.  The other switches between a selection of clock speeds (10Hz, 100Hz, 1kHz, 10kHz).  delay and microSecondDelay aren't very good so I used the micros() function to tell me how many microseconds since the last tick and transition the clock output at the end of an interval.

Button debounce is a nuisance so I used a simple Arduino ButtonDebounce library to control them.  I found this very effective.  You need to make sure your main loop executes quickly and include a button status update method for each button.  A callback then takes control when a valid press or release is identified leaving you to specify what happens next.

As I didn't want to connect the nano during operation I set up 3 LEDs to indicate the speed.  I used D13, which has the builtin LED attached, as my clock output so I can always see if the clock is running.  It is possible to see individual clock pulses at 10Hz, but after that the LED is continually lit.

Hardware Revision 5

Now that we have a more compact clock I can remove the Ben clock and add the LCD screen to the same breadboard segment.  I also added 4 buttons and an LED connected up to the remaining 5 VIA pins.  These are shown on Ben's 6502 photo but I haven't seen them discussed on his videos yet.

By the way I subscribed to Ben's patreon.  His tutorials have been massively informative and fun so I thought it only right to give something back.  He arranges it so you don't pay per week/month/quarter, you only contribute each time he releases a video, so I will continue to benefit as I contribute to his costs.

As I now have a good hardware build, I tidied up the wiring, to remove those long wires which always seem to get added as a design moves on.  I also purchased an FTDI cable so that I don't have my FTDI board sticking out.  With the buttons I use and the LCD and LEDs all at the bottom of the board I think Hardware rev 5 looks good.



What other hardware could I need?  Well an SD card would be good and some sort of integral graphics screen would help, but at the moment I feel they are luxuries.  I am happy I have a good environment with rev5 to write assembly programs with ample input / output facilities.

Diagnosis

When making changes to the hardware or even in normal use, it is possible that a bad connection will prevent the hardware from working.  There are proably 100 wires and 200 pin connections currently in the design.  A trial and error approach to fixing problems is often doomed to be a long and frustrating series of failures.

We keep the Arduino Mega attached to our 6502 system (primarily for downloading programs) and it is also vital for low level debugging.  Whith the 6502 clock stopped (i.e. in single step mode) we can use the eeprom-write sketch to test writing and reading the ROM, that is to say that we can check that ROM connections are working.
We also need to check the program in ROM is the one we expect.  If a different program is loaded, the 6502 may not be doing what we expect.  We can check the assembly listing output file against the executable loaded into ROM.

Next we check that 6502 boot sequence, stepping the processor and using the eeprom-monitor sketch.  This shows values loaded and after a reset it should be possible to see the reset vector FFFC and FFFD loading start address 8000.  Stepping a bit further will show us whether the stack is being used properly (i.e. RAM is working) as the first subroutine is executed. 

If the ROM, RAM and 6502 are ok the problem may lie with I/O.  Either a screen output program (using ACIA) or an LCD output (using VIA) should work so they can be checked independently.

This scheme should allow a failing component to be identified and individual pin signals can then be checked with an LED as necessary.

LED Flash

With a working 65C22 VIA, adding an LED output should be simple, it is only necessary to raise a VIA output pin high/low to turn on/off the LED.
In practice it is a little more difficult.  We have to write a byte to portA each time we change a bit, so if we are controlling the LCD with portA bits 5-7 we need to keep bit 0 as previously set so the LED is in the same state.  I thought that setting the pin as an input might preserve its state but the signal is turned off.  Consequently the LED bit has to be ORed with LCD bits before writing them.

Having worked this out it was an easy matter to set portA bit 0 to 1 or 0 for 255 clock cycles by decrementing an X register counter to zero in a loop and changing the LED pin state each time the value reached zero.  Unfortunately this ties up the processor so is very inefficient.  I will investigate a solution using interrupts, or perhaps a state machine.

TinyCAD

Having finished hardware rev 5 I should update the hardware schematic for Arduino Nano, LCD, LED and buttons.  I am learning the TinyCAD package so I can provide a better representation.  As the diagram becomes more complex the chances of errors increase.  As yet my skills have not advanced far enough for a complete schematic.

Sunday, 28 March 2021

6502 : Add RAM and VIA

 My 6502 system now has a working screen but as yet no RAM.  I find the idea of a working computer with no RAM strangely intruiging, but it is time to move on.  On the face of it, adding RAM is easy as I have done it before following the Ben Eater tutorial and its setup is very similar to the ROM.

RAM

Indeed 62256 memory connection is mostly straightforward.  The chip is located adjacent to the ROM and address/data pin connections are the same.  I rewired two existing NAND gates so they were in the same configuration as Ben's tutorial and used an extra NAND for RAM address wire setup as Ben did.

All worked well, with the proviso that it took a long time.  I found it vital to update the wiring schematic (now Hardware revison 3) before starting and to list out all the changes to existing wiring before I started.  As the circuit becomes more complex, any faults introduced can be very hard to identify.  Loose wires coming out are quite difficult to diagnose but an incorrect wiring change is even harder.

Initially I just added the RAM and wrote a small program to test reading/writing addresses and using the stack in a subroutine call.  I then moved theACIA serial chip from address $0000 where it conflicted with RAM to $6000, which Bens tutorial had previously made accessible for the VIA chip.

It feels very good indeed to have a computer with RAM, ROM, screen input / output which I can program easily in assembler language.  

VIA

To complete my basic computer I need to connect the Versatile Interface Adapter (VIA) so that I can access other peripherals.  I am hoping that this will be my last device attached to the 6502 directly as I have concerns I could mess it up or break it if I do too much tweaking.

Although Ben's initial LCD connection to VIA is not required, it does provide a useful test and confirm whether VIA is working so I connect / test the LCD as previously.

VIA connections are not complex, 8 data pins, 6 address related and 4 control pins.  I need an extra logic gate, and I connected a HCF4069 hex invertor for this.  I moved the A13 address pin from ACIA to VIA so that it uses address $6000.  I then inverted A13 as input to ACIA which is now at $4000.

I found that updating my schematic was vital before making connections as it is VERY easy to confuse yourself.  It is also sensible to write down each connection you need to make beforehand.  Thirdly, testing regularly that the original functions still work provides confidence that important existing pins have not been dislodged by the work.

On completion of the connections I could check that ACIA worked at its new address and then connect an LCD to the VIA as per Ben's instructions and check it work.  All is good, our computer now has RAM and I/O capabilities :) :) :)



Monday, 22 March 2021

6502 : Serial Terminal

 In my previous Ben Eater: 6502 post I set up a 6502 + EEPROM board with a Mega attached which enabled me to download programs with the ROM in situ.  As a second major enhancement, I need it have keyboard input and display output.  Ben does a diy video controller board but that looks painful.  Much more practical for me is to use a serial port with an emulated terminal.  I guess this isn't a pure solution, however I could make it one if I went on ebay to buy an old terminal.  In fact I did consider buying a real DEC VT100 as I used one for much of my (short) programming career but that would be overkill.

My objective is to provide a serial terminal input and output on my 6502 board using hardware compatible with the 6502 and EEPROM.  The best solution used by 6502 afficionados is an  ACIA (Asynchronous Communication Interface Adapter) W65C51 which interfaces to an FTDI chip and provides serial transmit / receive upto 19200bps.  An excellent example circuit and associated program is provided by Dirk Grappendorf.  I particularly liked that the program doesn't use RAM so I could proceed with the program before adding RAM to my computer (I never thought I would be able to say that).

Hardware

W65C51 chips are available on ebay for about £5, and they also require a 1.8432MHz oscillator (HC49) for another £1.




To check my understanding of the hardware I added the W65C51 to my board and connected up power, address, data and control pins (output-enable, chip-enable, write-enable).  I was then able to set pins in a sketch to control ACIA.  ACIA was setup with RS0=A0, RS1=A1 and /CS1=/A15 so that ACIA registers can be accessed at addresses 0000, 0001, 0002, 0003. 

I could then send a character to the serial port at 19200baud with 3 commands:
  Write 0B to address 0002             (for no parity, no echo, no interrupt)
  Write 1F to address 0003              (1 stop bit, 8 data bits, 19200 baud)
  Write characters to address 0000
 

6502 Connection

Once I knew the hardware was connected properly and working I could write a program.  For the previous test 6502 and EEPROM were turned off, so I turned them on and tried saving the simplest possible program to EEPROM and running it from the 6502.

loop:
  8000 LDA #0B             A9 0B    
  8002 STA $0002          85 02   store COMMAND byte
  8004 LDA #1F              A9 1F   store CONTROL byte
  8006 STA $0003          85 03
  8008 LDA #6A             A9 6A   write letter "j" on terminal
  800a STA $0000          85 00
  800c JMP loop           4C 00 80 start from the beginning

I used the monitor sketch to debug the program.  It was easy to have a bad or incorrect connection so I spent some time producing and checking the schematic above to ensure my hardware was set up as expected.  I used a couple of NAND gates to get the ROM and ACIA addressing signals as I wanted them.  In the listing below you can see the three write commands at lines 59,64 and 69.


Software

With a simple program working I could concentrate on providing a working programming environment. Initially I used VASM to compile a simple program and then manually transcribed the bytes into an array in a sketch for download to the EEPROM.  However this quickly became painful and I wrote a small utility program in C to read the VASM hex output file and format it into a text file which was included in my sketch as progdata.h.

Initially I had lots of manual intervention to stop the clock, download data, start clock and reset the 6502/ACIA.  It was easy to get the mega to sketch control the reset and clock pins during EEPROM download. 


I now have an easy programming environment which only requires two steps (1) compile program and format output into a sketch (2) download the sketch with clock paused, then reset the processor.

In the test program I used screen codes to erase and colour text to give a nicer result.