HI Eric,
It's only 16 bytes so it's very simple. ;16 BYTE BOOT STRAP TO LOAD PROGRAM FROM SERIAL PORT. 0000 211000 LXI HL,$0010 ;First free location 0003 DB00 IN 00 ;GET UART STATUS 0005 07 RLC ;SHIFT DAV TO CARRY FLAG 0006 DA0300 JC $0003 ;LOOP BACK UNTIL RXCHAR 0009 DB01 IN 01 ;GET CHAR 000B 77 MOV M,A ;SAVE IN MEMORY 000C 23 INX HL ;ADVANCE MEMORY 000D C30300 JMP $0003 ;LOOP BACK FOR NEXT CHAR After you toggle it in, you can reset and run, then have your PC send binary characters to be stored at address $0010 and up. I was using a small VB program I wrote that just opened a binary file and sent the bytes. There's no error checking, but it worked well enough to get a basic monitor into RAM. I also wrote up a decent monitor that includes XModem. I'll send this as an attachment. You will need to assemble it. You can delete the Floppy Disk section, since that will only work with the Tarbell MDL 1011 controller (or any other WD 1771 based FDD controller). I am assuming in this code that your SSM IO-4 is strapped for Altair Mode (this was how mine is/was strapped when I got the IMSAI). After the file transfer is complete, reset the computer, replace the first byte (21) with C3 to cause a Jump to $0010, then flip the run switch. If you want to try loading my Monitor program in, then add something like: .ORG 0010h JMP MAINMENU Also, check where "MAINPROGRAM" equates to, this has to point to RAM space. That is so strange that all those 8080A's aren't working for all codes... I am thinking something is still wrong with your CPU and/or FP boards. Perhaps try slowing down your clock? You might be able to just drop a different crystal into the 8224 circuit. It's expecting a series cut crystal, my knowledge ends here, so I can't say if a parallel cut crystal would work, my guess is there's no harm in trying. Toss in a 32Khz crystal, that should make for a nice and slow system, then you can definitely scope for bus noise, or contention. From: er...@osmancrew.com To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1495] New/Old Project (Altair restoration) Date: Sat, 9 Mar 2013 10:26:18 -0800 Hi
Josh -
If
that yellow jack on the new TVs will work, then I should be fine, as we have a
small one that isn't being used, except occasionally in the guest
room.
I'd be
interested in your 16 byte bootstrap, if you're willing to share. My old
bootstrap was considerably longer and I'll need to do something along those
lines until I get some kind of ROM board going. Eventually, I'd like to
get to the point where it us using a virtual floppy or hard drive on
flash.
I took
a couple hours out last night to test four old 8080 chips I had lying
around. The one I've been using is a recent purchase from Jameco, an
actual Intel part, amazingly enough. Anyway, they all "kind of"
work. In other words, they will properly execute some instructions and not
others. I found this surprising. I would have thought they would
either not work at all, or work 100%.
Back
to taxes.
-
Eric
-----Original Message-----
From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On Behalf Of Crusty OMO Sent: Thursday, March 07, 2013 6:02 AM To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1493] New/Old Project (Altair restoration) Eric,
I totally understand time restrictions on these projects. I thought it would take me 4 months to get my IMSAI running, but between family, work and other projects it took a solid 13 months and there's still more I'd like to do. It's like every new idea spawns two more. Even interest in this hobby waxes and wanes. I'm aware that new TV's no longer have the analog tuner but most if not all of the new TV's I've seen still have a Yellow RCA jack for plain NTSC video input. But, you probably don't want to use your main TV, instead, try to sit your wife down in front of it with a chick flick while you tinker with the Altair. For this purpose, it's not a bad idea to find an older TV, something more retro to match the Altair. Or you can also find security monitors, they all take standard video in. Check your local craigslist listing, I'm sure you'll find many bargains. I also see many old TV's for $10 or less at garage sales. PS. I also have a SSM IO-4 card. Getting your system to boot up will require a monitor in ROM, or some kind of floppy disk system. The ROM card is cheaper, Rich Cini uses a similar approach, if you search the forum or his site you can find more info on the RAM/ROM card he's using. It's a very cool board, because it lets you pop out the 2K RAM chip and replace it with a 2K ROM chip for that part of the memory map. Before I got my system to boot, I would toggle in a 16 byte boot strap to load programs from the PC. It's fun to do the first dozen times, then it gets old and you start to wonder how much wear and tear you want to put on your switches. Regards, Josh From: er...@osmancrew.com To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1491] New/Old Project (Altair restoration) Date: Wed, 6 Mar 2013 21:17:22 -0800 Hi
Josh -
Your suggestion to clean the edge connectors and slots is a
good one and I will be doing that soon. I'm going to have to reduce the
time I spend on this project for a while so I can get my taxes done and do some
other things to keep the wife happy. But I still plan to try to put 3 or 4
hours a week into it.
Here's a question: The Processor Technology VDM-1 puts out
composite video. My old TV with composite video input is long gone.
What do people recommend for converting composite video into something a modern
monitor can use?
That SBC you're putting together looks pretty ambitious. It will be
interesting to see the circuit diagrams when you get done. Maybe I'll
build a copy one of these days. But first, of course, I need to
finish getting all my current hardware working, which will be quite a
project in itself:
o
Another Altair CPU card
o
Two Processor Tech 4K SRAM cards
o A
processor Technology VDM-1
o A
Thinkertoys 32K SRAM card
o A
Solid State Music IO-4 card
Then there's the matter of setting up some way of booting something
useful, even just a monitor, with a minimum of switch flipping. I'd
forgotten how tedious and error prone that is.
-
Eric
-----Original Message-----
From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On Behalf Of Crusty OMO Sent: Wednesday, March 06, 2013 2:10 PM To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1489] New/Old Project (Altair restoration) Hey Eric, You made a good point about testing the RAM for hours. I only ran my tests for a few loops, not more than 30 minutes, but I should be testing it like you are doing for a solid 24+ hours. I find the edge card connectors need a good scrubbing, and you gotta get into the S-100 edge card sockets too. I wrote about this recently, if it was to you, then forgive me for repeating. To get into the sockets, cut one of those white rubber erasers into 1/16" thick slices and press it in and out of the socket, be sure to brush, vacuum and blow the sockets clean afterward. This is great that you've got a good point to start from. It can be very frustrating when everything that can go wrong has gone wrong. I had a weird (conditional) problem on my I/O card, but lost my patience and replaced 6 possible chips. I fixed the problem but didn't learn anything in the process. I just recently powered up a home brew 8080 card for another IMSAI I'm working on. The cpu didn't work right away, there were issues. FIrst it was the ready line that wasn't Active due to an I/O interface latch, next I found that I didn't wire the HOLD and INT lines, so they did go Active! Then another chip didn't have VCC connected, got that working but the CPU control (Examine/Deposit) didn't work (added some more logic to disable the RAM while operating the CPU). Lots of little problems, but I can't tear myself away from working on it, too damn addictive! Look for another post to Andrew for more details on this card if you want to see pictures. Cheers, Josh From: er...@osmancrew.com To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1488] New/Old Project (Altair restoration) Date: Tue, 5 Mar 2013 21:05:42 -0800 Hi
Josh -
Thanks!
Well that 32K RAM card didn't work out as well
as I hoped. It failed a memory test sporadically so I decided to
concentrate for now on my good, old 1K RAM card from MITS. After tracking
down several problems with the support logic, I just went ahead and replaced it
all. Then I wound up replacing one of the RAM chips. When running
diagnostics it would stop with a dropped bit after anywhere from 2 to 6 hours
and this would occur on any of the RAM chips, including the one I
replaced. Always bit zero. I was running this diagnostic on the 1K
card with the 32K card still in the system. I decided to remove the 32K
RAM card and move the 1K card right next to the CPU. It has now run over
26 hours with no dropped bits, although it has stopped twice when the memory
protect turned on by itself.
So
I'm thinking I have a noisy bus and will need to do something about that before
I can make more progress toward a reliable system. I have a terminated bus
on the way, but it will be a few days. Then I'll have to use a proto card
to hook the front panel into the bus. All 70 wires, approximately.
Yuk.
I
hear what you're saying about the older memory cards being unreliable. I
hope I'm able to get mine working because I'd like to keep the system as close
to "original" as possible. Of course swapping out the bus isn't exactly
original, but that old Altair bus really sucks. Alternatively, I could try
adding a terminator card to the end of the Altair bus.
Once I have a reliable system, even with just 1K of
RAM, I'll have a known good base from which to start trying to fix the other
cards.
Thanks for all your help.
-
Eric
-----Original Message-----
From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On Behalf Of Crusty OMO Sent: Wednesday, February 27, 2013 11:26 PM To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1477] New/Old Project (Altair restoration) Hi Eric, Excellent work! Yes, you are right about the RESET line needing to be low, sorry that was my mistake. I thought it was a "NOT" RESET line, that's why I put an asterix after the name RESET*. FYI, In the old S-100 bus descriptions, an asterix indicates a "NOT" logic pulse, eg Pin 77 is pWR* for "NOT" Write. My IMSAI also has a noisy o1 and o2, see picture attached. Perhaps you can improve your wave forms by adding some decoupling capacitors near the clock? You might have dirty edge card connections. Get a nice white polymer eraser and give the pcboard fingers a good scrubbing. I even slice the eraser into pcboard thickness and press in to the connectors. Just be sure to fish or blow out all the rub-off. On the IMSAI, I tried several memory boards, they all were flakey. I had to build a new RAM card with modern chips. Later RAM tests confirmed my suspicions on those old memory boards. But, overall it sounds like you are well on your way to fix everything. Looking Good! Regards, Josh From: er...@osmancrew.com To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1476] New/Old Project (Altair restoration) Date: Wed, 27 Feb 2013 19:51:09 -0800 Hi
Josh -
I went through all the checks you suggested and everything looked
good. The only exception is that I found reset on pin 12 to be
low instead of high. This is what I would expect based on my
reading. Was that a typo, or am I missing something?
Some of the waveforms were a bit ratty, but OK, I guess. I don't
want to clutter everyone's inboxes with a bunch of pictures, so I'm only
attaching one. It is of the two clock phases on pins 15 and 22 of the CPU
chip. This was a real eye opener to me a relative neophyte. Not the
pretty square waves they show in the book, that's for sure.
After replacing the one 8T97 and getting much better voltages on the bus
associated with those lines I went ahead and replaced all of them all and viola,
I have a CPU board that seems to work! The front panel functions seem to
work as well.
I
plugged in a recently acquired 32K static RAM board and everything seemed to
work except that I could deposit to memory using the front panel, but the CPU
did not seem to be able to write to memory. However, it started
working when I plugged the memory card into a different slot.
Spooky. I haven't yet put it back in the original slot to see what happens
but this seems like a problem I'd better get to the bottom
of.
I
also have another CPU card and a few RAM cards to get
working.
Thanks again for all your help.
-
Eric
-----Original Message-----
From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On Behalf Of Crusty OMO Sent: Monday, February 25, 2013 8:01 PM To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1472] New/Old Project (Altair restoration) Hi Eric, That does sound like good news. Those 8T97's on the 2nd CPU board might be the issue there. Sockets on all the chips shouldn't make a big difference, just as long as they are decent sockets. The only very sensitive chip that you might not want to socket is the Crystal Oscillator chip, 7404. How's your soldering? did you give a good visual for solder shorts? I like to hold the board up with a bright light behind so the board glows, you can see solder shorts and/or micro shorts. That's wonderful that you have a 2nd board. Now you can compare signal pulses between them. Go pin by pin on the CPU board, make your notes or take pictures. Yes, it does eat lots of time. I have the same frustration with time. Every project turns into hours, but I love doing it so those hours pass by so fast! But rest assured, you will find the problem(s) and fix if you keep studying the schematic, datasheets, etc The victory in the end is worth it! :) Cheers, Josh From: er...@osmancrew.com To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1471] New/Old Project (Altair restoration) Date: Mon, 25 Feb 2013 11:59:49 -0800 Hi
Josh -
Thanks for all the pointers and ideas.
Voltage levels to CPU chip OK.
I
wired up a proto board to pull the DI lines low for the NOP test as you
suggested. Going through a 100 ohm resistor didn't seem to successfully
pull the lines low, so I tied directly to ground.
I
still observe very flaky behavior with that CPU board that I can't begin to
characterize. You've got me wondering if those sockets I put on that board
were a good idea.
I
have another used Altair CPU board I bought a few years ago in anticipation of
this project. When I tried it the address bus does "count" as you suggest,
but that board has its own problems. I can stop the processor and
reset. Examine next seems to work, if I look real close at the
lights. This got me to checking the voltage levels on the address bus
(with the processor stopped). "High" is in the range of 1V. "Low" is
in the range of 0.1V. This varies a bit from one address line to the
next. For some lines "high" is in the range of 1.5V which is enough to
actually light the LED on the front panel. Recall that with the first
CPU card (the one I rebuilt) I was seeing more like 3.4V. I verified that
the addresses output to the 8T97 from the CPU chip are in the +5V
range. I notice the 8T97 seems to be getting fairly warm so it must be
dissipating all that voltage internally for some reason.
My
current plan is to pull one of the 8T97s from this CPU and put a socket in there
to see if a new 8T97 works better. If I can get a known working CPU I feel
like I can begin to debug any problems I may have on the front
panel.
Fun
stuff. Eating lots of time.
Thanks again. I really appreciate your help.
-
Eric
-----Original Message-----
From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On Behalf Of Crusty OMO Sent: Sunday, February 24, 2013 9:44 PM To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1468] New/Old Project (Altair restoration) Hi Eric, Yes, you must have the front panel in place. It is required to put the CPU in a "RUN" mode. The front panel controls or generates the CPU mode (RUN, WAIT or RESET). The 2 lines of interest are the pRESET (pin 75 on the S-100) and XRDY (pin 3). Other S-100 lines of interest are pRDY (pin 72), and pHOLD (pin 74). When running the NOP test, you want to scope every pin on the CPU to understand what it's doing. Look at the timing diagrams of the 8080A data sheet. 1st check the voltage pins (good idea to check ground pin 2 with ohm meter prior to powering system). 2nd check the CPU clocks, Pin 22 & 15 should have non-overlapping positive pulses to 12V. These are not TTL inputs. 3rd check the CPU mode, Reset* pin 12 must be high, Ready pin 23 must be high, Hold pin 13 must be low, INT pin 14 should be low. The mode inputs should be steady, no pulses. 4th check the CPU timing output pulses. WR* pin 18 should be high (we're executing NOP's, there should be no memory writes), DBIN should be pulsing high to fetch/read the NOP instructions, Sync pin 19 should be pulsing high during M1 of every cycle as per the data sheet. 5th Scope your data lines, these should be LOW (as tied low for the NOP) during the DBIN pulses, some pins should pulse high during the PSYNC to indicate M1 and sMEMR cycles (read the data sheet). 6th Scope your address lines, these should be counting up, you should see them all toggling high/low. Follow this signal onto the S-100 bus. The advantage of running NOP's, is that the CPU wave forms are repetitive and easy to follow on the scope. Also, it eliminates all other memory and I/O boards, breaks your system down to the basics. See CPU run. Run CPU run. Once you can get this far, it's likely that your system will operate if the other boards are good. But getting here isn't always so easy. I did a similar test to fix my OHIO Superboard. It was working intermittently with the NOP test. The problem was bad sockets, to make things a challenge, when I would scope a pin, the pressure put on that pin would make it temporarily connect. I think the Altair used good quality sockets, but best to keep your wits about you! Please keep in mind that I'm running an IMSAI 8080, but I think it's almost an identical copy of the Altair. Cheers, Josh From: er...@osmancrew.com To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1452] New/Old Project (Altair restoration) Date: Sat, 23 Feb 2013 21:54:57 -0800 Hi
Josh -
I
assume I can leave the front panel hooked up for the NOP test? I dread the
thought of removing and replacing all those wires again.
I
actually have three different 8080 chips and the computer doesn't work with any
of them, although the symptoms change slightly. In any case I have a new
one on order "just in case". It is true that none of the three are
"known good", so I like the idea of this test, I just hope I can do it with the
front panel in place.
-
Eric
-----Original Message-----
From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On Behalf Of Crusty OMO Sent: Saturday, February 23, 2013 9:29 PM To: n8vem...@googlegroups.com Subject: RE: [N8VEM-S100:1449] New/Old Project (Altair restoration) Hi Eric, Very cool! I have an IMSAI 8080. I checked the address lines and I also get 3.43V. Using 8T97 chips. You are right about the LS chips not being an exact replacement for the standard chips. They will work well enough as drop in replacements for digital circuits, but a crystal oscillator is an analog circuit. I have seen such oscillators fail with same part numbers by different manufacturers. That same oscillator circuit even failed by simply installing a socket. Trust me, I didn't believe it at first but after installing and removing it a few times, I recognize that crystal oscillators using TTL are very sensitive. Lee Hart has taught me that CMOS chips make much better choices for crystal oscillators. Back to your Altair. The 3.4V should work fine, it does on my system. The ring looks big, but I don't believe it's beyond a reasonable amount for a functioning system. You can probably reduce the ring by terminating that line, but it's quite likely you don't need to. May I recommend a "NOP" test? Remove all boards except the CPU. Pull the DI0-7 lines low. Ground them or use 100 ohm. There shouldn't be anything driving those DI lines, so be suspicious if you read voltage on those lines. This is the NOP command, let the CPU run, now scope all the lines. Look for pSync, o1, o2, clock, MEMR, DBIN. The address lines should be counting. Check your CPU for correct voltage, check the WAIT, HOLD and RESET signals. Your CPU must be running, if not, then you have a bad CPU chip. If anything isn't right, trace the signals back to the front panel switches. Check that DI0-7 is reaching the CPU through the buffer chip. I hope that idea helps. good luck. Josh
> From: er...@osmancrew.com > To: n8vem...@googlegroups.com > Subject: RE: [N8VEM-S100:1447] New/Old Project (Altair restoration) > Date: Sat, 23 Feb 2013 20:07:43 -0800 > > > With advice from Tom Lafleur and others I've been making some progress on my > Altair restoration. This machine was killed by a lightning induced power > surge many years ago. I've installed new, modern power supplies, and I've > removed all the chips from the front panel and the CPU. These were replaced > with sockets. I learned that apparently, you can't always replace 74xx with > 74LSxx. I learned this when the system clock would not run when I tried two > different 74LS04 chips in the clock circuit but works fine with a 7404. > > Anyway, after repopulating the chip sockets with mostly LS parts, the Altair > exhibits very strange and unstable behavior. I almost don't know where to > begin to describe it. Let's just say that the results of a reset are fairly > random. > > I thought I'd ask a few specific questions: > If I "stop" the Altair and check the voltage of an address line on the bus > that is high, I get about 3.4 volts. The only boards in the system are the > front panel and the CPU. In this configuration, all that's going on is the > 8080 address lines are buffered through 74LS367’s onto the bus. The front > panel is involved only insofar as the address lines each go through an LED > and a 220 ohm resistor to ground to display the address line's state. Hard > to imagine a simpler situation. The output from the 8080 is a healthy 4.9V > where it goes into the 74LS367, but on the output side it is only 3.4V. > This low voltage value for a high logic state seems like a potential problem > to me. Am I right? > > Lest you think it might be a bad 74LS367, be aware that I previously had the > functionally equivalent 8T97 chips in there and had essentially the same > result. > > Also, the CPU and front panel regulators were replaced and I get a healthy > 4.96V on the +5 side of the regulators. > > So the immediate questions are: > 1. Am I right in saying that the 3.4V level is an issue? > 2. If so, any ideas what could be causing this? > 3. I'm attaching the oscilloscope trace of the system clock as seen on bus > line 49. Does that look OK, or is there too much ringing? > > CPU Schematic here: > http://www.s100computers.com/Hardware%20Manuals/MITS/8080%20CPU%20Board%20Sc > hematic.pdf > > Thanks for your ideas. > > - Eric Osman > > -----Original Message----- > From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On > Behalf Of Eric Osman > Sent: Saturday, February 02, 2013 12:48 PM > To: n8vem...@googlegroups.com > Subject: RE: [N8VEM-S100:1357] New/Old Project > > > Douglas - > > Thanks for the introduction and summary. I'm on Andrew's list for an > extender, and I'll probably be looking to obtain a prototyping card as well. > These are driven by my initial goal, which is just to get my Altair working > again. Longer term I'll be looking to enhance it a bit. > > I was intrigued enough by the Raspberry Pi to get one, but of course, that > is not the focus of this board. > > I'll be looking over the Wiki's and mail group archives that you mentioned. > > Thanks again. > > - Eric > > -----Original Message----- > From: n8vem...@googlegroups.com [mailto:n8vem...@googlegroups.com]On > Behalf Of Douglas Goodall > Sent: Saturday, February 02, 2013 10:52 AM > To: n8vem...@googlegroups.com > Subject: Re: [N8VEM-S100:1355] New/Old Project > > > Eric, > > Our group consists of lots of old-timers and youth as well. > > Apparently all of us like to fiddle with hardware, and there is quite a lot > of fun going on. > > The major interests within the group are focused on a range of hardware, as > simple as a single > board computer (See the Zeta), and more sophisticated buss oriented systems, > both S-100 and ECB. > > Andrew supplies bare circuit boards for us, mini boards, SBC's, and a highly > integrated machine we > started calling the N8 (originally named "Home Computer"). > > John sells S-100 bare boards, CPU cards, memory boards, ... > > There are two main Google mail groups, one for Andrew's focus > (n8...@googlegroups.com) and one > for John's (n8vem...@googlegroups.com). There is another one recently > formed for the scsi to ide > project, aka S2I. > > Information about the boards, schematics, board layouts, etc are found on > the wiki (n8vem-sbc.pbworks.com). > > Building these boards is a learning experience, and we gain knowledge about > sourcing parts, building up > boards and then debug them. The community members are very happy to help > each other get things working > the google groups are a constant stream of questions and answers about > aspects of the hardware and > software. > > There are a number of different BIOSs written by community members, some of > which are more specific and > some of which are more productized and full featured. If you want to find > out more about the boards, look > under board information on the wiki. There is a software information section > as well. > > Welcome to our community, and don't be shy to communicate with us via the > lists or privately. > > Regards, > > Douglas Goodall > > On Feb 2, 2013, at 1:23 AM, Eric O <ewo...@gmail.com> wrote: > > > Andrew Lynch suggested I join this group and seek assistance with my > "project". > > > > Background: > > Back in 1975 I was a 20 year-old electrical engineering college student > and electronics hobbyist and saw the famous Popular Electronics article on > the Altair 8800 computer. I ordered it, assembled it and it worked great as > soon as I powered it on for the first time. Over the next year or three I > enhanced it with some additional memory, a homebrew parallel and serial > interface and the Processor Technology video card. I wrote hand-assembled > machine code to "boot load" my own little monitor via a modem to the > mainframe computer on campus. This involved an automated log-in to my > account, starting the listing of a hex file and then capturing and loading > that hex file into the Altair RAM. Of course I had to switch a couple > hundred bytes of machine code into the Altair whenever I needed to "reboot". > I also wrote a terminal emulation program so I could then use it as a > terminal to that same mainframe. Great fun and done on a shoe string > because I was a very poor college student. > > > > Disaster literally struck out of the sky one day around 1979 when a very > powerful thunderstorm hit and a lightning bolt literally blew the top off > the power pole that fed the off-campus house I shared with three other > students. I should have unplugged the Altair when the thunderstorm arrived, > but I didn't want to have to take 15 minutes to reboot it. Stupid! Anyway > the power surge killed the machine. It would still light up but it wouldn't > do anything approaching normal operation. I did replace a number of the > chips in the weeks that followed, but I couldn't afford to do a proper job > of it. > > > > Well, graduation came, then a job, then an IBM 5150, and then other > computers over the decades and now the Altair has been stored in a box for > almost 35 years. I always meant to fix it someday but never got around to > it. But now that I'm semi-retired from a career in computers I'm finally > getting around to it. So a couple months ago I finally got it out of that > box and started doing a bit of research and I'm so happy to see all the love > that people have for these old machines. > > > > One of the first things I learned was not to trust the original power > supply. So I went out and got a couple switching power supplies from > MeanWell, mounted them up in the chassis, and leaving the old supply > physically in place, removed it electrically and replaced it with the new > supply. > > > > I popped out all the boards, and turned it on. I'm getting all the proper > voltages in all the proper places, including regulated +5.13 on the display > board. With the CPU in I get the proper regulated voltages on the CPU card: > (-5.25 on Pin 11, +11.69 on pin 28, +5.00 out of the regulator). > > > > I've started working on the front panel and I've already identified two > inverters with the same logic state on each side of the gate, on two > different chips. So I know I need to replace those. > > > > Any and all suggestions welcome. > > > > (I've seen the very good article at > http://s100computers.com/My%20System%20Pages/Debugging/Debugging%20for%20beg > inners.htm) > > > > Eric O > > > > -- > > You received this message because you are subscribed to the Google Groups > "N8VEM-S100" group. > > To unsubscribe from this group and stop receiving emails from it, send an > email to n8vem-s100+...@googlegroups.com. > > For more options, visit https://groups.google.com/groups/opt_out. > > > > > > --- > Douglas Goodall, http://goodall.com > > Note: I don't use messenger, or skype, or facebook, chat programs in > general. Having always-on open communication links through massive public > servers I don't have control over seems like too much of an invitation to be > infected by a virus or bot. It is bad enough that my Mac wants to stay in > periodic contact with Apple's cloud. Skype was tempting before Microsoft > bought them. There have been too many examples of remote session links being > abused by vendor employees. Even "back to my mac" makes me nervous. There > was a recent episode where Apple cooperated with a social engineer and > compromised someone's entire electronic persona. If you want to speak with > me, calling me on the phone works well, and you don't have to wonder if the > electronic mail got through or not. When I say "Hello, this is Doug", you > know who you are talking to. Just in case you were curious. > > -- > You received this message because you are subscribed to the Google Groups > "N8VEM-S100" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to n8vem-s100+...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- > You received this message because you are subscribed to the Google Groups > "N8VEM-S100" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to n8vem-s100+...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > -- > You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. > To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. -- You received this message because you are subscribed to the Google Groups "N8VEM-S100" group. To unsubscribe from this group and stop receiving emails from it, send an email to n8vem-s100+...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out. |
;File for boot Disk ;Include Boot Loader ;Convert Hex file (.OBJ) to BIN ;Upload BIN to Disk at logical sector 0000 ; ; ;Version 1.7 - Josh Bensadon. Added Unassemble command ****CAUTION**** This routine has 3 tables that must NOT cross page boundaries. ;Version 1.6 - Josh Bensadon. Added RAM tests ;Version 1.5 - Josh Bensadon. Rewrote dump, to allow ASCII display to the right of HEX dump (similar to DOS DEBUG) ;Version 1.4 - Josh Bensadon. Added boot strap sector to allow monitor to be loaded directly from disk, no more EPROM ;Version 1.3 - Josh Bensadon. Restructured XModem for RAM and Disk transfers ;Version 1.2 - Josh Bensadon. Modified HEX input routines - Allow Space and Enter ;Version 1.1 - Josh Bensadon. Added Floppy Disk for Tarbell Controller ;Version 1.0 - Josh Bensadon. Added XModem & HEX upload, changed CP/M I/O to standard Altair I/O via console port at I/O ports 0 & 1 ;Version 0.1 (c) 2012 Jonathan Chapman, http://www.glitchwrks.com ; ;Monitor for the IMSAI 8080 ;Functions: ; -Dump, Edit & Execute Memory. ; -Input Port and Output Port. ; -RAM Test ; -ASCII Upload text file ; -XMODEM up/down load to Memory ; -Floppy Format,Read,Write,Test Disks ; -XMODEM up/down load to Disk ; ; AA8080.ASM works with the Standard Console port of the Altair (Port 0=Status, Port 1=RX/TX) ; Tested on the Solid State Music Computer Systems IO4 Serial/Parallel interface board installed on an IMSAI 8080 ; Floppy functions work with the Tarbell 1101 (using the Western Digital FD1771 Floppy Disk Controller chip). ; ; D XXXX YYYY Dump memory from XXXX to YYYY ; E XXXX Edit memory starting at XXXX (type an X and press enter to exit entry) ; G XXXX GO starting at address XXXX (Monitor program address left on stack) ; I XX Input from I/O port XX and display as hex ; O XX YY Output to I/O port XX byte YY ; X U XXXX XMODEM Upload to memory at XXXX (CRC or CHECKSUM) ; X D XXXX CCCC XMODEM Download from memory at XXXX for CCCC number of 128 byte blocks ; :ssHHLLttDDDDDD...CS -ASCII UPLOAD Intel HEX file to Memory. Monitor auto downloads with the reception of a colon. ; F Floppy commands ; R XX YY RAM TEST from pages XX to YY ; ; Search for BIOS sections to adapt to other systems BOOTSTRAP .EQU 0000H MAINPROGRAM .EQU BOOTSTRAP + 0100H ;Assemble Hi Monitor ;MAINPROGRAM .EQU 8000H ;----------------------------------------------------------------------------------------------------; IMSAI CONSOLE PORTS ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; IMSAI CONSOLE PORTS FPLED .EQU 255 ;Front Panel LED FPSW .EQU 255 ;Front Panel Switches ;----------------------------------------------------------------------------------------------------; HARD BOOTSTRAP ON 82S123 PROM ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ON TARBELL 1101 FDC CONTROLLER ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; HARD BOOTSTRAP ON 82S123 PROM ; .ORG 100H ;TEST ROM BOOT STRAP. ;BOOT: IN WAIT ; XRA A ; MOV L,A ; MOV H,A ; INR A ; OUT SECT ; MVI A,8Ch ; OUT DCOM ;RLOOP: IN WAIT ; ORA A ; JP RDONE ; IN DDATA ; MOV M,A ; INX H ; JMP RLOOP ;RDONE IN DSTAT ; STA 80H ; JMP MAIN_MENU ;----------------------------------------------------------------------------------------------------; SECTOR 1 BOOT LOADER ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; SECTOR 1 BOOT LOADER ; TARBELL ELECTRONICS ; CP/M COLDSTART LOADER ; VERSION OF 3-22-'79. ; ; THIS PROGRAM IS LOADED AT LOCATION ZERO BY THE BOOTSTRAP PROGRAM, AND EXECUTED. ; ITS PURPOSE IS TO LOAD AND EXECUTE THE MONITOR PROGRAM FROM DISK ; ; ;********* THIS IS THE AREA TO MAKE CHANGES IN *********** ;********* FOR DIFFERENT SYSTEM CONFIGURATIONS *********** ; ** SPT .EQU 26 ;NUMBER OF SECTORS PER TRACK. ** DISK .EQU 0F8H ;DISK PORT BASE ADDRESS. ** ; ** ;********************************************************* ;********************************************************* ;DSTAT .EQU 0F8H ;DCMD .EQU 0F8H ;DTRACK .EQU 0F9H ;DSECTOR.EQU 0FAH ;DDATA .EQU 0FBH ;DWAIT .EQU 0FCH DCOM .EQU DISK ;COMMAND PORT. DSTAT .EQU DISK ;STATUS PORT. TRACK .EQU DISK+1 ;TRACK PORT. SECT .EQU DISK+2 ;SECTOR PORT. DATA .EQU DISK+3 ;DATA PORT. WAIT .EQU DISK+4 ;WAIT PORT. PGMLD .EQU 80H ;START OF PROGGRAM BOOTE .EQU 100H ;COLD BOOT ENTRY POINT. NSECTS .EQU 51 ;SECTORS OF CP/M. RTCNT .EQU 10 ;NUMBER OF RETRYS. .IF 0 .ORG BOOTSTRAP ;START OF LOADER. BOOT: MVI E,RTCNT ;GET RETRY COUNT. BLOOP: LXI H,PGMLD ;PROGRAM STARTS HERE. MVI D,NSECTS ;NUMBER OF SECTORS TO READ. MVI C,2 ;SECTOR NUMBER. RNTRK: MVI B,4 ;FOR HEAD LOAD. MOV A,C ;SECTOR IN A RNSEC: OUT SECT ;SET SECTOR REGISTER. IN DSTAT ;READ STATUS. ANI 9DH ;LOOK AT ERROR BITS. JNZ RERR ;JUMP IF ERROR MVI A,88H ;COMMAND FOR READ. ORA B ;GET HEAD LOAD BIT. OUT DCOM ;ISSUE COMMAND. RLOOP: IN WAIT ;WAIT FOR DRQ. ORA A ;SET FLAGS. JP RNEXT ;JUMP IF DONE. IN DATA ;READ DATA. MOV M,A ;PUT IN MEMORY. INX H ;INCREMENT POINTER. JMP RLOOP ;LOOP UNTIL DONE. RNEXT: IN DSTAT ;READ STATUS. ANI 9DH ;LOOK AT ERROR BITS. JNZ RERR ;JUMP IF ERROR DCR D ;IF DONE, JZ BOOTE ;GO TO MONITOR (NOT CP/M) MVI B,0 ;FOR NO HEAD LOAD. INR C ;INCREMENT SECTOR NUMBER. MOV A,C ;DONE WITH CPI SPT+1 ;THIS TRACK? JC RNSEC ;IF NOT, READ NEXT SECTOR. MVI A,053H ;STEP IN COMMAND. OUT DCOM ;ISSUE IT. IN WAIT ;WAIT UNTIL DONE. MVI C,1 ;SECTOR NUMBER. JMP RNTRK ;READ NEXT TRACK. RERR DCR E ;DECREMENT RETRY COUNT. JNZ BLOOP ;TRY AGAIN IF NOT ZERO. STA EC ;SAVE ERROR CODE. CMA ;INVERT AND SEND OUT FPLED ;TO FRONT PANEL. HERE: JMP HERE ;LOOP. .ORG 7DH ;PUT JUMP HERE, TARBELL ROM JUMPS TO THIS ADDRESS TO START THE BOOT LOADER JMP BOOT ;JUMP INTO BOOT. ;BOOT STACK 0FFH .ENDIF .ORG MAINPROGRAM ;----------------------------------------------------------------------------------------------------; MAIN MENU ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; MAIN MENU MAIN_MENU: JMP CODE_START ;----------------------------------------------------------------------------------------------------; RAM SPACE ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; RAM SPACE SKEW_TBL .db 0,1,4,7,10,13,16,19,22,25,2,5,8,11,14,17,20,23,26,3,6,9,12,15,18,21,24 ; .db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 EC: .DB 0 ;ERROR CODE XMSEQ .DB 0 ;XMODEM SEQUENCE NUMBER XMTYPE .DB 0 ;XMODEM BLOCK TYPE (CRC/CS) ECHO_ON .DB 1 ;Echo characters RES .DB 0 ;ROUTINE RESULTS (1=HOME, 2=FORMAT, FF=LEAD OUT FAILED) RES1 .DB 0 ;DSTAT RESULTS RES2 .DB 0 ;COUNT OF LEAD OUT BYTES RES3 .DB 0 ;COUNT OF LEAD OUT BYTES $1531 HLWRITE .DW 0 ;Last address +1 of Bytes Written to disk HLREAD .DW 0 ;Last address +1 of Bytes Read from disk XSECTOR .DB 0 ;Sector of xmodem transfer XTRACK .DB 0 ;Track of xmodem transfer XCOUNT .DW 0 ;Count of sectors to read XSUM .DW 0 ;Sum of Staring Sector & Count XPOS .DW 0 ;Position of next read/write logical sector CODE_START LXI SP,100h LXI H, MAIN_MENU ;Push Mainmenu onto stack as default return address PUSH H CALL PRINTI ;Monitor Start, Display Welcome Message .text "\r\nIMSAI 8080 Monitor V1.7 - Josh Bensadon\r\n>\000" MVI A,0FFH STA ECHO_ON ;TURN ON ECHO CALL GET_CHAR ;get char CPI ':' JZ GETHEXFILE ; : = START HEX FILE LOAD ANI 5Fh ;to upper case CPI 'D' ;Branch to Command entered JZ MEM_DUMP ; D = Memory Dump CPI 'E' JZ MEM_EDIT ; E = Edit Memory CPI 'G' JZ MEM_EXEC ; G = Go (Execute at) CPI 'O' JZ PORT_OUT ; O = Output to port CPI 'I' JZ PORT_INP ; I = Input from Port CPI 'X' JZ XMODEM ; X = XMODEM CPI 'F' JZ FLOPPY_MENU ; F = FLOPPY CPI 'R' JZ RAM_TEST ; R = RAM TEST CPI 'U' JZ MEM_UNASM ; U = UNASSEMBLE CALL PRINTI ;Display Err when input is invalid .text "\r\nSP=\000" LXI H,0 DAD SP CALL PUT_HL CALL PRINTI ;Display Err when input is invalid .text " PC=\000" CALL GET_PC GET_PC POP H CALL PUT_HL CALL PRINTI ;Display Err when input is invalid .text "\r\nHELP" .text "\r\nD - Dump" .text "\r\nE - Edit" .text "\r\nG - Go (Exec)" .text "\r\nO - Output to port" .text "\r\nI - Input to port" .text "\r\nX - XModem Up/Down Load" .text "\r\nF - Floppy Routines" .text "\r\nR - RAM TEST" .text "\r\nU - Unassemble" .text "\r\n>\000" JMP MAIN_MENU ;============================================================================= ;MEMORY UNASSEMBLE ;----------------------------------------------------------------------------- MEM_UNASM: CALL SPACE_GET_WORD ;Input start address XCHG ;HL = Start CALL PUT_NEW_LINE XRA A STA ECHO_ON ;TURN OFF ECHO MU_LP1 MVI B,10 MU_LP2 PUSH B CALL DISASM POP B DCR B JNZ MU_LP2 CALL GET_CHAR CPI 27 JNZ MU_LP1 RET ;============================================================================= ;MEMORY DUMP ;----------------------------------------------------------------------------- MEM_DUMP: CALL SPACE_GET_WORD ;Input start address XCHG ;HL = Start CALL SPACE_GET_WORD ;Input end address (DE = end) MEM_DUMP_LP: CALL PUT_NEW_LINE CALL DUMP_LINE ;Dump 16 byte lines (advances HL) RZ ;RETURN WHEN HL=DE MOV A,L ORA A JNZ MEM_DUMP_LP ;Dump 1 Page, then prompt for continue CALL GET_CONTINUE JMP MEM_DUMP_LP GET_CONTINUE CALL PUT_NEW_LINE CALL PRINTI .text "Press any key to continue\000" CALL GET_CHAR CPI 27 RNZ POP H ;Scrap return address RET ;----------------------------------------------------------------------------- ;DUMP_LINE -- Dumps a line ;xxx0: <pre spaces> XX XX XX XX XX After spaces | ....ASCII.... ;----------------------------------------------------------------------------- DUMP_LINE: PUSH B ;+1 PUSH H ;+2 Save H for 2nd part of display PUSH H ;+3 Start line with xxx0 address MOV A,L ANI 0F0h ;Mask FFF0 MOV L,A CALL PUT_HL ;Print Address CALL PRINTI .text ": \000" POP H ;-3 MOV A,L ANI 0Fh ;Fetch how many prespaces to print MOV C,A MOV B,A ;Save count of prespaces for part 2 of display CALL PUT_3C_SPACES DL_P1L CALL PUT_SPACE MOV A,M CALL PUT_BYTE CALL CMP_HL_DE JZ DL_P1E INX H MOV A,L ANI 0Fh JNZ DL_P1L JMP DL_P2 DL_P1E MOV A,L CMA ANI 0Fh MOV C,A CALL PUT_3C_SPACES DL_P2 CALL PRINTI ;Print Seperator between part 1 and part 2 .text " | \000" DL_PSL2 MOV A,B ;Print prespaces for part 2 ORA A JZ DL_PSE2 CALL PUT_SPACE DCR B JMP DL_PSL2 DL_PSE2 POP H ;-2 POP B ;-1 DL_P2L MOV A,M CPI ' ' ;A - 20h Test for Valid ASCII characters JP DL_P2K1 MVI A,'.' ;Replace with . if not ASCII DL_P2K1 CPI 07Fh ;A - 07Fh JM DL_P2K2 MVI A,'.' DL_P2K2 CALL PUT_CHAR CALL CMP_HL_DE RZ INX H MOV A,L ANI 0Fh JNZ DL_P2L ;----------------------------------------------------------------------------- ;Compare HL with DE ;Exit: Z=1 if HL=DE ; M=1 if DE > HL CMP_HL_DE MOV A,H CMP D ;H-D RNZ ;M flag set if D > H MOV A,L CMP E ;L-E RET PUT_3C_SPACES MOV A,C ;Print 3C Spaces ORA A RZ DCR C ;Count down Prespaces CALL PRINTI ;Print pre spaces .text " \000" JMP PUT_3C_SPACES ;----------------------------------------------------------------------------- ;EDIT MEMORY ;Edit memory from a starting address until X is pressed. ;Display mem loc, contents, and results of write. ;----------------------------------------------------------------------------- MEM_EDIT: CALL SPACE_GET_WORD ;Input Address XCHG ;HL = Address to edit ME_LP CALL PUT_NEW_LINE CALL PUT_HL ;Print current contents of memory CALL PUT_SPACE MVI A, ':' CALL PUT_CHAR CALL PUT_SPACE MOV A, M CALL PUT_BYTE CALL SPACE_GET_BYTE ;Input new value or Exit if invalid RC ;Exit to Command Loop MOV M, A ;or Save new value CALL PUT_SPACE MOV A, M CALL PUT_BYTE INX H ;Advance to next location JMP ME_LP ;repeat input ;============================================================================= ; MEM_EXEC - Execute at ; Get an address and jump to it ;----------------------------------------------------------------------------- MEM_EXEC: CALL SPACE_GET_WORD ;Input address XCHG ;HL = Address PCHL ;Jump to HL ;============================================================================= SPACE_GET_BYTE CALL PUT_SPACE ;============================================================================= ;GET_BYTE -- Get byte from console as hex ; ;in: Nothing ;out: A = Byte (if CY=0) ; A = non-hex char input (if CY=1) ;----------------------------------------------------------------------------- GET_BYTE: CALL GET_HEX_CHAR ;Get 1st HEX CHAR JNC GB_1 CPI ' ' ;Exit if not HEX CHAR (ignoring SPACE) JZ GET_BYTE ;Loop back if first char is a SPACE STC ;Set Carry RET ;or EXIT with delimiting char GB_1 PUSH D ;Process 1st HEX CHAR RLC RLC RLC RLC ANI 0F0h MOV D,A CALL GET_HEX_CHAR JNC GB_2 ;If 2nd char is HEX CHAR CPI ' ' JZ GB_RET1 STC ;Set Carry POP D RET ;or EXIT with delimiting char GB_2 ORA D POP D RET GB_RET1 MOV A,D RRC RRC RRC RRC GB_RET ORA A POP D RET ;============================================================================= SPACE_GET_WORD CALL PUT_SPACE ;============================================================================= ;GET_WORD -- Get word from console as hex ; ;in: Nothing ;out: A = non-hex char input ; DE = Word ;----------------------------------------------------------------------------- GET_WORD: LXI D,0 CALL GET_HEX_CHAR ;Get 1st HEX CHAR JNC GW_LP CPI ' ' ;Exit if not HEX CHAR (ignoring SPACE) JZ GET_WORD ;Loop back if first char is a SPACE ORA A ;Clear Carry RET ;or EXIT with delimiting char GW_LP MOV E,A CALL GET_HEX_CHAR RC ;EXIT when a delimiting char is entered XCHG ;Else, shift new HEX Char Value into DE DAD H DAD H DAD H DAD H XCHG ORA E JMP GW_LP ;=============================================== ;Get HEX CHAR ;in: Nothing ;out: A = Value of HEX Char when CY=0 ; A = Received (non-hex) char when CY=1 ;----------------------------------------------- GET_HEX_CHAR: CALL GET_CHAR CPI '0' JM GHC_NOT_RET CPI '9'+1 JM GHC_NRET CPI 'A' JM GHC_NOT_RET CPI 'F'+1 JM GHC_ARET CPI 'a' JM GHC_NOT_RET CPI 'f'+1 JM GHC_ARET GHC_NOT_RET STC RET GHC_ARET SUI 07h GHC_NRET ANI 0Fh RET ;=============================================== ;ASCHEX -- Convert ASCII coded hex to nibble ; ;pre: A register contains ASCII coded nibble ;post: A register contains nibble ;----------------------------------------------- ASCHEX: SUI 30h CPI 0Ah RM ANI 5Fh SUI 07h RET ;=============================================== ;PUT_HL Prints HL Word ;----------------------------------------------- PUT_HL: MOV A, H CALL PUT_BYTE MOV A, L ; CALL PUT_BYTE ; RET ;=============================================== ;PUT_BYTE -- Output byte to console as hex ; ;pre: A register contains byte to be output ;post: Destroys A ;----------------------------------------------- PUT_BYTE: PUSH PSW RRC RRC RRC RRC ANI 0Fh CALL PUT_HEX POP PSW ANI 0Fh ; CALL PUT_HEX ; RET ;=============================================== ;PUT_HEX -- Convert nibble to ASCII char ; ;pre: A register contains nibble ;post: A register contains ASCII char ;----------------------------------------------- PUT_HEX: ADI 90h DAA ACI 40h DAA JMP PUT_CHAR ;=============================================== ;Input from port, print contents PORT_INP: CALL SPACE_GET_BYTE MOV B, A CALL PUT_SPACE MVI C, 0DBh CALL GOBYTE CALL PUT_BYTE RET ;Get a port address, write byte out PORT_OUT: CALL SPACE_GET_BYTE MOV B, A CALL SPACE_GET_BYTE MVI C, 0D3h ;=============================================== ;GOBYTE -- Push a two-byte instruction and RET ; and jump to it ; ;pre: B register contains operand ;pre: C register contains opcode ;post: code executed, returns to caller ;----------------------------------------------- GOBYTE: LXI H, 0000 DAD SP ;HL = STACK DCX H MVI M, 0C9h ;Stuff RET instruction in STACK RAM DCX H MOV M, B ;Stuff Port DCX H MOV M, C ;Stuff Input or Output instruction PCHL ;=============================================== ;PUT_SPACE -- Print a space to the console ; ;pre: none ;post: 0x20 printed to console ;----------------------------------------------- PUT_SPACE: MVI A, ' ' JMP PUT_CHAR ;=============================================== ;PUT_NEW_LINE -- Start a new line on the console ; ;pre: none ;post: 0x0A printed to console ;----------------------------------------------- PUT_NEW_LINE: MVI A, 13 CALL PUT_CHAR MVI A, 10 JMP PUT_CHAR ;=============================================== ;PRINT -- Print a null-terminated string ; ;pre: HL contains pointer to start of a null- ; terminated string ;----------------------------------------------- PRINT: MOV A, M INX H ORA A RZ CALL PUT_CHAR JMP PRINT ;=============================================== ;PRINT IMMEDIATE ;----------------------------------------------- PRINTI: XTHL ;HL = Top of Stack CALL PRINT XTHL ;Move updated return address back to stack RET ;----------------------------------------------------------------------------------------------------; ASCII HEXFILE TRANSFER ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; ASCII HEXFILE TRANSFER GETHEXFILE MVI A,0 MOV E,A ;ZERO ERROR COUNTER STA ECHO_ON ;TURN OFF ECHO JMP GHDOLINE GHWAIT CALL GET_CHAR CPI ':' JNZ GHWAIT GHDOLINE CALL GET_BYTE ;GET BYTE COUNT MOV C,A ;BYTE COUNTER MOV D,A ;CHECKSUM CALL GET_BYTE ;GET HIGH ADDRESS MOV H,A ADD D MOV D,A CALL GET_BYTE ;GET LOW ADDRESS MOV L,A ADD D MOV D,A CALL GET_BYTE ;GET RECORD TYPE CPI 1 JZ GHEND ;IF RECORD TYPE IS 01 THEN END ADD D MOV D,A GHLOOP CALL GET_BYTE ;GET DATA MOV M,A ADD D MOV D,A INX H DCR C JNZ GHLOOP CALL GET_BYTE ;GET CHECKSUM ADD D JZ GHWAIT INR E JNZ GHWAIT DCR E JMP GHWAIT GHEND CALL PRINTI .text "\r\nHEX TRANSFER COMPLETE ERRORS=\000" MOV A,E CALL PUT_BYTE JMP PURGE ;----------------------------------------------------------------------------------------------------; XMODEM ROUTINES ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; XMODEM ROUTINES SOH .equ 1 ;Start of Header EOT .equ 4 ;End of Transmission ACK .equ 6 DLE .equ 16 DC1 .equ 17 ; (X-ON) DC3 .equ 19 ; (X-OFF) NAK .equ 21 SYN .equ 22 CAN .equ 24 ;(Cancel) ;--------------------------------------------------------------------------------- ;XMODEM MENU ;ENTRY: TOP OF STACK HOLDS RETURN ADDRESS (EXIT MECHANISM IF XMODEM IS CANCELLED) ;--------------------------------------------------------------------------------- XMODEM CALL PUT_SPACE CALL GET_CHAR ;get char ANI 5Fh ;to upper case CPI 'D' JZ XMDN ; D = DOWNLOAD CPI 'U' JZ XMUP ; U = UPLOAD CALL PRINTI .text "?\000" RET ;--------------------------------------------------------------------------------- ;XMDN - XMODEM DOWNLOAD (send file from IMSAI to Terminal) ;INPUT STARTING ADDRESS AND COUNT OF BLOCKS (WORD) ;WAIT FOR 'C' OR NAK FROM HOST TO START CRC/CS TRANSFER ;--------------------------------------------------------------------------------- XMDN CALL SPACE_GET_WORD ;Input Address XCHG ;HL = Address to SAVE DATA CALL SPACE_GET_WORD ;Input #Blocks to Send ;DE = Count of Blocks MOV A,D ORA E RZ ;Exit if Block Count = 0 ;HL = Address of data to send from the IMSAI 8080 ;DE = Count of Blocks to send. CALL XMS_INIT ;Starts the Seq, Sets the CS/CRC format ;Cancelled Transfers will cause a RET XMDN_LP CALL XMS_SEND ;Sends the packet @HL, Resends if NAK ;Cancelled Transfers will cause a RET DCX D MOV A,D ORA E JNZ XMDN_LP CALL XMS_EOT ;Send End of Transmission JMP PURGE ;--------------------------------------------------------------------------------- ;XMUP - XMODEM UPLOAD (receive file from Terminal to IMSAI 8080) ;INPUT STARTING ADDRESS ;SEND 'C' OR NAK TO HOST TO START CRC/CS TRANSFER ;--------------------------------------------------------------------------------- XMUP CALL SPACE_GET_WORD ;Input Address XCHG ;HL = Address to SAVE DATA ;HL = Address of data to send from the IMSAI 8080 CALL XMR_INIT ;Starts the transfer & Receives first PACKET ;Cancelled Transfers will cause a RET XMUP_LP CALL XMR_RECV ;Receives the next packet @HL, Resends if NAK ;Cancelled Transfers will cause a RET JC XMUP_LP ;Jump until EOT Received JMP PURGE ;--------------------------------------------------------------------------------- ;INIT FOR SENDING XMODEM PROTOCOL, GET NAK OR 'C', SAVE THE XMTYPE ;--------------------------------------------------------------------------------- XMS_INIT INR D ;Pre increment high count register for last block test MVI A,1 ;First SEQ number STA XMSEQ MVI B,10 ;10 retries for initiating the transfer XMS_INIT_LP MVI A,45 ;GET CHAR, 45 SECONDS TIMEOUT (EXPECT C OR NAK) CALL TIMED_GETCHAR JC XM_CANCEL ;Cancel if Host Timed out CPI NAK ;If NAK, Start Checksum Download JZ XMS_DO CPI 'C' ;If C, Start CRC Download JZ XMS_DO DCR B ;Count down Retries JNZ XMS_INIT_LP JMP XM_CANCEL ;Cancel XModem if all retries exhausted XMS_DO STA XMTYPE RET ;--------------------------------------------------------------------------------- ;SEND A PACKET (RESEND UPON NAK) ;--------------------------------------------------------------------------------- XMS_RESEND LXI B,0FF80h DAD B XMS_SEND PUSH D MVI A,SOH ;SEND THE HEADER FOR CRC OR CHECKSUM CALL PUT_CHAR LDA XMSEQ CALL PUT_CHAR CMA CALL PUT_CHAR LXI D,0000H ;Init DE=0000 (CRC Accumulator) MVI C,0 ;Init C=00 (CS Accumulator) MVI B,128 ;Count 128 bytes per block XMS_BLP MOV A,M ;Fetch bytes to send -------------------\ CALL PUT_CHAR ;Send them ADD C ;Update the CS MOV C,A MOV A,M CALL CRC_UPDATE ;Update the CRC INX H ;Advance to next byte in block DCR B ;Count down bytes sent JNZ XMS_BLP ;Loop back until 128 bytes are sent -----^ LDA XMTYPE CPI NAK ;If NAK, send Checksum JZ XMS_CS ;----------------------v MOV A,D ;else, Send the CRC next CALL PUT_CHAR MOV C,E XMS_CS MOV A,C ;----------------------/ CALL PUT_CHAR ;Packet Sent, get Ack/Nak Response MVI A,45 ;GET CHAR, 45 SECONDS TIMEOUT (EXPECT C OR NAK) CALL TIMED_GETCHAR POP D JC XM_CANCEL ;Cancel download if no response within 45 seconds CPI NAK JZ XMS_RESEND ;Loop back to resend packet CPI CAN JZ XM_CANCEL CPI ACK JNZ XM_CANCEL LDA XMSEQ INR A ;NEXT SEQ STA XMSEQ RET ;--------------------------------------------------------------------------------- ;XMDN - DOWNLOAD XMODEM PACKET ;--------------------------------------------------------------------------------- XMS_EOT MVI A,EOT ;HANDLE THE END OF TRANSFER FOR CRC OR CHECKSUM CALL PUT_CHAR MVI A,45 ;GET CHAR, 45 SECONDS TIMEOUT (EXPECT C OR NAK) CALL TIMED_GETCHAR JC XM_CANCEL CPI NAK JZ XMS_EOT CPI ACK JNZ XM_CANCEL XM_DONE CALL PRINTI .text "\r\nTRANSFER COMPLETE\r\n\000" XRA A ;CLEAR A, CY RET ;FINISHING CODE PRIOR TO LEAVING XMODEM XM_CANCEL MVI A,CAN CALL PUT_CHAR CALL PUT_CHAR CALL PURGE CALL PRINTI .text "TRANSFER CANCELED\r\n\000" POP B ;SCRAP CALLING ROUTINE AND HEAD TO PARENT RET ;--------------------------------------------------------------------------------- ;START XMODEM RECEIVING and RECEIVE FIRST PACKET ;--------------------------------------------------------------------------------- XMR_INIT MVI E,5 ;5 ATTEMPTS TO INITIATE XMODEM CRC TRANSFER MVI A,1 ;EXPECTED SEQ NUMBER starts at 1 STA XMSEQ XMR_CRC CALL PURGE MVI A,'C' ;Send C STA XMTYPE ;Save as XM Type (CRC or CS) CALL PUT_CHAR CALL XMGET_HDR ;Await a packet JNC XMR_TSEQ ;Jump if first packet received JNZ XM_CANCEL ;Cancel if there was a response that was not a header DCR E ;Otherwise, if no response, retry a few times JNZ XMR_CRC MVI E,5 ;5 ATTEMPTS TO INITIATE XMODEM CHECKSUM TRANSFER XMR_CS CALL PURGE MVI A,NAK ;Send NAK STA XMTYPE ;Save as XM Type (CRC or CS) CALL PUT_CHAR CALL XMGET_HDR ;Await a packet JNC XMR_TSEQ ;Jump if first packet received JNZ XM_CANCEL ;Cancel if there was a response that was not a header DCR E ;Otherwise, if no response, retry a few times JNZ XMR_CS JMP XM_CANCEL ;Abort ;--------------------- XMODEM RECEIVE ;Entry: XMR_TSEQ in the middle of the routine ;Pre: C=1 (expected first block as received when negogiating CRC or Checksum) ; HL=Memory to dump the file to ;Uses: B to count the 128 bytes per block ; C to track Block Number expected ; DE as CRC (Within Loop) (D is destroyed when Getting Header) ;------------------------------------ XMR_RECV MVI A,ACK ;Send Ack to start Receiving next packet CALL PUT_CHAR XMR_LP CALL XMGET_HDR JNC XMR_TSEQ PUSH H JZ XMR_NAK ;NACK IF TIMED OUT POP H CPI EOT JNZ XM_CANCEL ;CANCEL IF CAN RECEIVED (OR JUST NOT EOT) MVI A,ACK CALL PUT_CHAR JMP XM_DONE XMR_TSEQ MOV C,A LDA XMSEQ CMP C ;CHECK IF THIS SEQ IS EXPECTED JZ XMR_SEQ_OK ;Jump if CORRECT SEQ DCR A ;Else test if Previous SEQ STA XMSEQ CMP C JNZ XM_CANCEL ;CANCEL IF SEQUENCE ISN'T PREVIOUS BLOCK CALL PURGE ;ELSE, PURGE AND SEND ACK (ASSUMING PREVIOUS ACK WAS NOT RECEIVED) JMP XMR_ACK XMR_SEQ_OK MVI B,128 ;128 BYTES PER BLOCK MVI C,0 ;Clear Checksum LXI D,0000H ;CLEAR CRC PUSH H ;Save HL where block is to go XMR_BLK_LP CALL TIMED1_GETCHAR JC XMR_NAK MOV M,A ;SAVE DATA BYTE CALL CRC_UPDATE MOV A,M ;Update checksum ADD C MOV C,A INX H ;ADVANCE DCR B JNZ XMR_BLK_LP ;After 128 byte packet, verify error checking byte(s) LDA XMTYPE ;Determine if we are using CRC or Checksum CPI NAK ;If NAK, then use Checksum JZ XMR_CCS CALL TIMED1_GETCHAR JC XMR_NAK CMP D JNZ XMR_NAK CALL TIMED1_GETCHAR JC XMR_NAK CMP E JNZ XMR_NAK JMP XMR_ACK XMR_CCS CALL TIMED1_GETCHAR JC XMR_NAK CMP C JNZ XMR_NAK ;If we were transfering to a FILE, this is where we would write the ;sector and reset HL to the same 128 byte sector buffer. ;CALL WRITE_SECTOR XMR_ACK ;MVI A,ACK ;The sending of the Ack is done by ;CALL PUT_CHAR ;the calling routine, to allow writes to disk LDA XMSEQ INR A ;Advance to next SEQ BLOCK STA XMSEQ POP B STC ;Carry set when NOT last packet RET XMR_NAK POP H ;Return HL to start of block CALL PURGE MVI A,NAK CALL PUT_CHAR JMP XMR_LP ;--------------------- XMODEM - GET HEADER ; ;pre: Nothing ;post: Carry Set: A=0, (Zero set) if Timeout ; Carry Set: A=CAN (Not Zero) if Cancel received ; Carry Set: A=EOT (Not Zero) if End of Tranmission received ; Carry Clear and A = B = Seq if Header found and is good ;------------------------------------------ XMGET_HDR MVI A,5 ;GET CHAR, 5 SECONDS TIMEOUT (EXPECT SOH) CALL TIMED_GETCHAR RC ;Return if Timed out CPI SOH ;TEST IF START OF HEADER JZ GS_SEQ ;IF SOH RECEIVED, GET SEQ NEXT CPI EOT ;TEST IF END OF TRANSMISSION JZ GS_ESC ;IF EOT RECEIVED, TERMINATE XMODEM CPI CAN ;TEST IF CANCEL JNZ XMGET_HDR GS_ESC ORA A ;Clear Z flag (because A<>0) STC RET GS_SEQ CALL TIMED1_GETCHAR ;GET SEQ CHAR RC ;Return if Timed out MOV B,A ;SAVE SEQ CALL TIMED1_GETCHAR ;GET SEQ COMPLEMENT RC ;Return if Timed out CMA CMP B ;TEST IF SEQ VALID JNZ XMGET_HDR ;LOOP BACK AND TRY AGAIN IF HEADER INCORRECT (SYNC FRAME) RET ;------------------------------------------ CRC_UPDATE ;HANDLE THE CRC CALCULATION FOR UP/DOWNLOADING ;Total Time=775 cycles = 388uSec ;In: A = New char to roll into CRC accumulator ; DE = 16bit CRC accumulator ;Out: DE = 16bit CRC accumulator ;------------------------------------------ ;CRC_UPDATE XRA D ;4 ; MOV D,A ;5 ; PUSH B ;11 ; MVI B,8 ;7 PRELOOP=27 ;CRCU_LP ORA A ;4 CLEAR CARRY ; MOV A,E ;5 ; RAL ;4 ; MOV E,A ;5 ; MOV A,D ;5 ; RAL ;4 ; MOV D,A ;5 ; JNC CRCU_NX ;10 ; MOV A,D ;5 ; XRI 10h ;7 ; MOV D,A ;5 ; MOV A,E ;5 ; XRI 21H ;7 ; MOV E,A ;5 ;CRCU_NX DCR B ;5 ; JNZ CRCU_LP ;10 LOOP=91*8 (WORSE CASE) ; POP B ;10 POSTLOOP=20 ; RET ;10 ;------------------------------------------ CRC_UPDATE ;HANDLE THE CRC CALCULATION FOR UP/DOWNLOADING ;Total Time=604 cycles = 302uSec MAX ;In: A = New char to roll into CRC accumulator ; DE = 16bit CRC accumulator ;Out: DE = 16bit CRC accumulator ;------------------------------------------ CRC_UPDATE XCHG ;4 XRA H ;4 MOV H,A ;5 DAD H ;10 Shift HL Left 1 CC CRC_UPC ;17 (10/61) DAD H ;10 Shift HL Left 2 CC CRC_UPC ;17 DAD H ;10 Shift HL Left 3 CC CRC_UPC ;17 DAD H ;10 Shift HL Left 4 CC CRC_UPC ;17 DAD H ;10 Shift HL Left 5 CC CRC_UPC ;17 DAD H ;10 Shift HL Left 6 CC CRC_UPC ;17 DAD H ;10 Shift HL Left 7 CC CRC_UPC ;17 DAD H ;10 Shift HL Left 8 CC CRC_UPC ;17 XCHG ;4 RET ;10 CRC_UPC MOV A,H ;5 XRI 10h ;7 MOV H,A ;5 MOV A,L ;5 XRI 21H ;7 MOV L,A ;5 RET ;10 ;XModem implementation on 8080 Monitor (CP/M-80) ; ;Terminal uploads to 8080 system: ;-Terminal user enters command "XU aaaa" ;-8080 "drives" the protocol since it's the receiver ;-8080 sends <Nak> every 10 seconds until the transmitter sends a packet ;-if transmitter does not begin within 10 trys (100 seconds), 8080 aborts XMODEM ;-a packet is: ; <SOH> [seq] [NOT seq] [128 bytes of data] [checksum or CRC] ; ;<SOH> = 1 (Start of Header) ;<EOT> = 4 (End of Transmission) ;<ACK> = 6 ;<DLE> = 16 ;<DC1> = 17 (X-ON) ;<DC3> = 19 (X-OFF) ;<NAK> = 21 ;<SYN> = 22 ;<CAN> = 24 (Cancel) ; ;Checksum is the Modulo 256 sum of all 128 data bytes ; ; <<<<< [NAK] ; [SOH][001][255][...][csum] >>>>> ; <<<<< [ACK] ; [SOH][002][254][...][csum] >>>>> ; <<<<< [ACK] ; [SOH][003][253][...][csum] >>>>> ; <<<<< [ACK] ; [EOT] >>>>> ; <<<<< [ACK] ; ;-if we get <EOT> then ACK and terminate XModem ;-if we get <CAN> then terminate XModem ;-if checksum invalid, then NAK ;-if seq number not correct as per [NOT seq], then NAK ;-if seq number = previous number, then ACK (But ignore block) ;-if seq number not the expected number, then <CAN><CAN> and terminate XModem ;-if data not received after 10 seconds, then NAK (inc Timeout Retry) ;-if timeout retry>10 then <CAN><CAN> and terminate XModem ; ;-To keep synchronized, ; -Look for <SOH>, qualify <SOH> by checking the [seq] / [NOT seq] ; -if no <SOH> found after 135 chars, then NAK ; ;-False EOT condtion ; -NAK the first EOT ; -if the next char is EOT again, then ACK and leave XModem ; ;-False <CAN>, expect a 2nd <CAN> ? ; ;-Using CRC, send "C" instead of <NAK> for the first packet ; -Send "C" every 3 seconds for 3 tries, then degrade to checksums by sending <NAK> ; ; ; ;* The character-receive subroutine should be called with a ;parameter specifying the number of seconds to wait. The ;receiver should first call it with a time of 10, then <nak> and ;try again, 10 times. ; After receiving the <soh>, the receiver should call the ;character receive subroutine with a 1-second timeout, for the ;remainder of the message and the <cksum>. Since they are sent ;as a continuous stream, timing out of this implies a serious ;like glitch that caused, say, 127 characters to be seen instead ;of 128. ; ;* When the receiver wishes to <nak>, it should call a "PURGE" ;subroutine, to wait for the line to clear. Recall the sender ;tosses any characters in its UART buffer immediately upon ;completing sending a block, to ensure no glitches were mis- ;interpreted. ; The most common technique is for "PURGE" to call the ;character receive subroutine, specifying a 1-second timeout, ;and looping back to PURGE until a timeout occurs. The <nak> is ;then sent, ensuring the other end will see it. ; ;* You may wish to add code recommended by Jonh Mahr to your ;character receive routine - to set an error flag if the UART ;shows framing error, or overrun. This will help catch a few ;more glitches - the most common of which is a hit in the high ;bits of the byte in two consecutive bytes. The <cksum> comes ;out OK since counting in 1-byte produces the same result of ;adding 80H + 80H as with adding 00H + 00H. ;----------------------------------------------------------------------------------------------------; RAM TEST ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; RAM TEST ;B=START PAGE ;C=END PAGE RAM_TEST: CALL SPACE_GET_BYTE MOV B, A CALL SPACE_GET_BYTE MOV C, A ;Page March Test. 1 Sec/K ; ; FOR E = 00 TO FF STEP FF 'March 00 then March FF ; FOR H = B TO C ; PAGE(H) = E ; NEXT H ; FOR D = B TO C ; PAGE(D) = NOT E ; FOR H = B TO C ; A = E ; IF H = D THEN A = NOT E ; IF PAGE(H) <> A THEN ERROR1 ; NEXT H ; NEXT D ; NEXT E ; CALL PRINTI .text "\r\nTESTING RAM\000" MVI E,0FFh ;E selects the polarity of the test, ie March a page of 1'S or 0's ;Clear/Set all pages RT1_LP0 MOV H,B ;HL = BASE RAM ADDRESS MVI L,0 RT1_LP1 MOV A,E ;CLEAR A CMA RT1_LP2 MOV M,A ;WRITE PAGE INR L JNZ RT1_LP2 ;LOOP TO QUICKLY WRITE 1 PAGE MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT1_LP1 ;LOOP UNTIL = END PAGE ;March 1 PAGE through RAM MOV D,B ;Begin with START PAGE ;Write FF to page D RT1_LP3 MOV H,D ;HL = Marched Page ADDRESS ;MVI L,0 CALL ABORT_CHECK MOV A,D CMA OUT FPLED ;MOV A,E ;SET A RT1_LP4 MOV M,E ;WRITE PAGE INR L JNZ RT1_LP4 ;LOOP TO QUICKLY WRITE 1 PAGE ;Test all pages for 0 (except page D = FF) MOV H,B ;HL = BASE RAM ADDRESS ;MVI L,0 RT1_LP5 MOV A,H ;IF H = D CMP D MOV A,E ;THEN Value = FF JZ RT1_LP6 CMA ;ELSE Value = 00 RT1_LP6 CMP M ;TEST RAM JNZ RT_FAIL1 INR L JNZ RT1_LP6 ;LOOP TO QUICKLY TEST 1 PAGE MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT1_LP5 ;LOOP UNTIL = END PAGE ;Write 00 back to page D MOV H,D ;HL = Marched Page ADDRESS ;MVI L,0 MOV A,E CMA RT1_LP7 MOV M,A ;WRITE PAGE INR L JNZ RT1_LP7 ;LOOP TO QUICKLY WRITE 1 PAGE MOV A,D INR D ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT1_LP3 ;LOOP UNTIL = END PAGE INR E JZ RT1_LP0 CALL PRINTI .text "\r\nRAM PAGE MARCH PASSED\000" ;Byte March Test. 7 Sec/K ; ; FOR E = 00 TO FF STEP FF 'March 00 then March FF ; FOR H = B TO C ; PAGE(H) = E ; FOR D = 00 TO FF ; PAGE(H).D = NOT E ; FOR L=0 TO FF ; IF PAGE(H).L <> E THEN ; IF PAGE(H).L <> NOT E THEN ERROR2 ; IF L<>D THEN ERROR2 ; ENDIF ; NEXT L ; NEXT D ; NEXT H ; NEXT E MVI E,0FFh ;E selects the polarity of the test, ie March a page of 1'S or 0's ;Clear/Set all pages RT2_LP0 MOV H,B ;HL = BASE RAM ADDRESS RT2_LP1 MVI L,0 CALL ABORT_CHECK MOV A,H CMA OUT FPLED MOV A,E ;CLEAR A CMA RT2_LP2 MOV M,A ;WRITE PAGE INR L JNZ RT2_LP2 ;LOOP TO QUICKLY WRITE 1 PAGE MVI D,0 ;Starting with BYTE 00 of page RT2_LP3 MOV L,D ;Save at byte march ptr MOV A,E ;SET A MOV M,A ;MOV A,E CMA ;CLEAR A MVI L,0 RT2_LP4 CMP M ;TEST BYTE FOR CLEAR JZ RT2_NX1 CMA ;SET A CMP M ;TEST BYTE FOR SET JNZ RT_FAIL2 ;IF NOT FULLY SET, THEN DEFINITELY FAIL MOV A,L ;ELSE CHECK WE ARE ON MARCHED BYTE CMP D JNZ RT_FAIL2 MOV A,E ;CLEAR A CMA RT2_NX1 INR L JNZ RT2_LP4 ;LOOP TO QUICKLY WRITE 1 PAGE MOV L,D ;Save at byte march ptr MOV A,E CMA ;CLEAR A MOV M,A INR D JNZ RT2_LP3 MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT2_LP1 ;LOOP UNTIL = END PAGE INR E JZ RT2_LP0 CALL PRINTI .text "\r\nRAM BYTE MARCH 1 PASSED\000" ;26 Sec/K BYTEMARCH2 MVI E,0FFh ;E selects the polarity of the test, ie March a page of 1'S or 0's RT4_LP0 MVI D,0 ;Starting with BYTE 00 of page ;CLEAR all pages MOV H,B ;HL = BASE RAM ADDRESS MVI L,0 RT4_LP1 MOV A,E ;CLEAR A CMA RT4_LP2 MOV M,A ;WRITE PAGE INR L JNZ RT4_LP2 ;LOOP TO QUICKLY WRITE 1 PAGE MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT4_LP1 ;LOOP UNTIL = END PAGE RT4_LP3 CALL ABORT_CHECK MOV A,D CMA OUT FPLED ;Write SET byte at "D" in every page MOV H,B ;HL = BASE RAM ADDRESS MOV L,D ;Save at byte march ptr RT4_LP4 MOV M,E MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT4_LP4 ;LOOP UNTIL = END PAGE MVI L,0 RT4_LP5 MOV H,B ;HL = BASE RAM ADDRESS MOV A,L CMP D JZ RT4_LP7 ;Test for marked byte in all pages RT4_LP6 MOV A,E CMA ;CLEAR A CMP M ;TEST BYTE FOR CLEAR JNZ RT_FAIL2 MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT4_LP6 ;LOOP UNTIL = END PAGE JMP RT4_NX RT4_LP7 MOV A,E CMP M ;TEST BYTE FOR SET JNZ RT_FAIL2 MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT4_LP7 ;LOOP UNTIL = END PAGE RT4_NX INR L JNZ RT4_LP5 ;Write CLEAR byte at "D" in every page MOV H,B ;HL = BASE RAM ADDRESS MOV L,D ;Save at byte march ptr RT4_LP8 MOV A,E CMA MOV M,A MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT4_LP8 ;LOOP UNTIL = END PAGE INR D JNZ RT4_LP3 INR E JZ RT4_LP0 CALL PRINTI .text "\r\nRAM BYTE MARCH 2 PASSED\000" BIT_MARCH ;Bit March Test. 0.1 Sec/K MVI E,01 ;E selects the bit to march ;Clear/Set all pages RT3_LP1 MOV H,B ;HL = BASE RAM ADDRESS MVI L,0 CALL ABORT_CHECK MOV A,E ;Display bit pattern on LED PORT CMA OUT FPLED RT3_LP2 MOV A,E ;FETCH MARCHING BIT PATTERN RT3_LP3 MOV M,A ;WRITE PAGE INR L JNZ RT3_LP3 ;LOOP TO QUICKLY WRITE 1 PAGE MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT3_LP2 ;LOOP UNTIL = END PAGE MOV H,B ;HL = BASE RAM ADDRESS ; MVI L,0 RT3_LP4 MOV A,E ;FETCH MARCHING BIT PATTERN RT3_LP5 CMP M JNZ RT_FAIL3 INR L JNZ RT3_LP5 ;LOOP TO QUICKLY WRITE 1 PAGE MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT3_LP4 ;LOOP UNTIL = END PAGE ;0000 0010 ;... ;1000 0000 MOV A,E RAL ;ROTATE THE 01 UNTIL 00 MOV A,E RLC MOV E,A CPI 1 JNZ RT3_NX1 CMA ;INVERT ALL BITS MOV E,A JMP RT3_LP1 RT3_NX1 CPI 0FEh JNZ RT3_LP1 CALL PRINTI .text "\r\nRAM BIT MARCH PASSED\000" MVI E,01 ;E selects the start sequence ;Clear/Set all pages RT5_LP1 CALL ABORT_CHECK MOV A,E ;Display bit pattern on LED PORT CMA OUT FPLED MOV H,B ;HL = BASE RAM ADDRESS MVI L,0 MOV D,E RT5_LP2 INR D JNZ RT5_NX1 INR D RT5_NX1 MOV M,D ;WRITE PAGE INR L JNZ RT5_LP2 ;LOOP TO QUICKLY WRITE 1 PAGE MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT5_LP2 ;LOOP UNTIL = END PAGE MOV H,B ;HL = BASE RAM ADDRESS ;MVI L,0 MOV D,E RT5_LP3 INR D JNZ RT5_NX2 INR D RT5_NX2 MOV A,D CMP M ;TEST JNZ RT_FAIL5 INR L JNZ RT5_LP3 ;LOOP TO QUICKLY WRITE 1 PAGE MOV A,H INR H ;ADVANCE TO NEXT PAGE CMP C ;COMPARE WITH END PAGE JNZ RT5_LP3 ;LOOP UNTIL = END PAGE INR E JNZ RT5_LP1 CALL PRINTI .text "\r\nRAM SEQUENCE TEST PASSED\000" JMP MAIN_MENU RT_FAIL1 CALL PRINTI .text "\r\nRAM FAILED PAGE MARCH AT:\000" CALL PUT_HL JMP MAIN_MENU RT_FAIL2 CALL PRINTI .text "\r\nRAM FAILED BYTE MARCH AT:\000" CALL PUT_HL JMP MAIN_MENU RT_FAIL3 CALL PRINTI .text "\r\nRAM FAILED BIT MARCH AT:\000" CALL PUT_HL JMP MAIN_MENU RT_FAIL5 CALL PRINTI .text "\r\nRAM FAILED SEQUENCE TEST AT:\000" CALL PUT_HL JMP MAIN_MENU ;----------------------------------------------------------------------------------------------------; FLOPPY DISK ROUTINES ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; FLOPPY DISK ROUTINES ;FORMAT A DISK FROM CONSOLE LOADED PROGRAM ;http://www.hartetechnologies.com/manuals/Tarbell/Tarbell%20Single%20Density%20Disk%20Controller.pdf ;Floppy Drive Specs and facts: ;8" drive spins at 360RPM, that is 6 Revolutions per second ;Writing a track (ie formating) at single density (with the IBM 2740 Format of 26 sectors, each 128 bytes long). ;The Western Digital FD1771 controller data sheet states approx 5156 BYTES PER TRACK are required. ;The CRC's for each sector is calculated with in the FD1771 and written when a single command byte (F7) is encountered ;during the data sequence. There are 2 CRC's per Sector (one for the ID Address Field and one for the 128 byte data field). ;So upon read back, there will be another 26 X 2 bytes expected per track, bringing the total to ~5208 bytes. ;The exact byte count is not accurate due to Disk Speed and FD1771 Clock Frequency Variations. ;On my system, the byte count varies each time I format the track from 5212 up to 5232 bytes. ;From this approach, we must be able to transfer a byte every 32 microseconds (1/6/5208). ;From the data sheet, the time between clock bitts (TCW) is 4 microseconds. Since there is 1 clock pulse for every data bit, ;a byte is written in 32 microseconds (4 X 8 bits). ;Therefore, we must transfer data to/from the FD1771 at the rate of 32uSec per byte (or 250,000 bits per second). ; ;Specs about the IMSAI 8080 ; ; 8224 Clock is 18Mhz. ; Machine Cycle speed is 2Mhz ; Maximum allowed Machine cycles = 64 to service a Data Request (DRQ) ; ;Following is a code snipet to Write Disk: ; ; OUT DCMD ;LOOP: IN DWAIT ;(10) the Tarbell 1101 Controller puts the CPU into a WAIT state until the FD1771 raises DRQ or INTRQ ; ORA A ;(4) ; JP EXIT ;(10) JUMP WHEN INTRQ ; MOV A,M ;(7) GET BYTE ; OUT DDATA ;(10) SEND BYTE TO WRITE TO DISK ; INX H ;(5) ; JMP LOOP ;(10) Total=56 cycles in loop ; ;EXIT: IN DSTAT ;Read STATUS for any ERRORS ; ... ; ;The code snippet to Read Disk is almost the same, but with a data input and save to memory instruction instead. ; ;This code completes a loop in 56 cycles, which is adequate to read/write to the controller. ;The CPU will have 8 cycles of WAIT state through each itteration of the loop. ;The data is buffered by a 1 byte register within the FD1771, so Dynamic RAM can use as much as 8 cycles to refresh every 56 cycles. ;I do not know the requirements of DRAM to refresh and will not cover that here, but suffice to say, if more than 8 cycles are taken ;within a 64 cycle window, data speed to/from the FD1771 cannot be maintained and there will be errors in the transfer. ;In my IMSAI 8080, I am only using Static RAM (for now). ; ;EG RESULTS ;01 = (FORMAT TRACK COMPLETE) ;00 = (NO ERRORS) ;5D = 93 LEAD OUT BYTES FLOPPY_MENU: CALL PRINTI ;Display Err when input is invalid .text "\r\nFLOPPY MENU" .text "\r\n+ Track +" .text "\r\n- Track -" .text "\r\n/ Sector +" .text "\r\n* Sector -" .text "\r\nT Track Read" .text "\r\nY Track Read w/Sync" .text "\r\nU Track Write (Format)" .text "\r\nI Track Format w/Sector Verify Test" .text "\r\nO DISK Format w/Sector Verify Test" .text "\r\nS Sector Read" .text "\r\nD Sector Write" .text "\r\nR aaaa " .text "\r\n" .text "\r\n\000" DISKMENU_LP: CALL PUT_NEW_LINE MVI A,'T' CALL PUT_CHAR IN DTRACK CALL PUT_BYTE CALL PUT_SPACE MVI A,'S' CALL PUT_CHAR IN DSECTOR CALL PUT_BYTE CALL PUT_SPACE MVI A,'%' CALL PUT_CHAR CALL GET_CHAR ;CONTROL COMMANDS, Return to loop through JUMP CPI 27 ;Branch to Command entered RZ ; <ESC> = Exit CPI '?' ; JZ FLOPPY_MENU ; ? = Help CPI '+' ; JZ FTRKADV ; + = TRACK ADVANCE CPI '-' ; JZ FTRKRET ; - = TRACK RETARD CPI '*' ; JZ FSECADV ; * = TRACK ADVANCE CPI '/' ; JZ FSECRET ; / = TRACK RETARD ANI 5Fh ;to upper case ;ABORTABLE COMMANDS, Return by RET on stack LXI H,DISKMENU_LP PUSH H ;Save return address on stack CPI 'H' ;Branch to Command entered JZ FHOME ; H = HOME CPI 'T' JZ FREADT ; T = READ TRACK CPI 'Y' JZ FREADT0 ; Y = READ TRACK (W/SYNC) CPI 'U' JZ FFORMATT ; U = WRITE TRACK (FORMAT) CPI 'I' JZ FFORMATV ; I = WRITE TRACK (FORMAT) w/Sector Verify Test" CPI 'O' JZ FFORMATD ; O = DISK FORMAT w/Sector Verify Test" CPI 'S' ; JZ FSECREAD ; S = SECTOR READ CPI 'D' ; JZ FSECWRITE ; D = SECTOR WRITE CPI 'X' ; JZ FXMODEM ; X = XMODEM Transfers CPI 'V' ; JZ FTESTD ; V = VERIFY DISK RET ;JMP DISKMENU_LP ;************************************************************************************** CONTROL COMMANDS FTRKADV MVI A,53h ;----------------- FLOPPY: TRACK ADVANCE CALL DO_DCMD JMP DISKMENU_LP FTRKRET MVI A,73h ;----------------- FLOPPY: TRACK RETARD CALL DO_DCMD JMP DISKMENU_LP FSECADV IN DSECTOR ;----------------- FLOPPY: SECTOR ADVANCE INR A OUT DSECTOR JMP DISKMENU_LP FSECRET IN DSECTOR ;----------------- FLOPPY: SECTOR RETARD DCR A OUT DSECTOR JMP DISKMENU_LP ;************************************************************************************** ABORTABLE COMMANDS ;--------------------------------------------------------- FLOPPY: HOME FHOME MVI A,76 CALL FSEEK ;SEEK TO TRACK 76 JMP F_HOME_RESULT ;SEEK TO TRACK 00 ;--------------------------------------------------------- FLOPPY: READ TRACK FREADT0 MVI A,0E4H ;READ TRACK JMP FREADT_DO ;--------------------------------------------------------- FLOPPY: READ TRACK FREADT MVI A,0E5H ;READ TRACK FREADT_DO LXI H, TRACK_BUFFER CALL READ_CMD CALL PRINT_RES CALL PRINT_HL RET ;--------------------------------------------------------- FLOPPY: WRITE (FORMAT) TRACK (INTERACTIVE) FFORMATT CALL FCONFIRM CALL FFORMATDO CALL PRINT_RES CALL PRINT_HL RET ;--------------------------------------------------------- FLOPPY: WRITE/FORMAT TRACK w/Verify (INTERACTIVE) FFORMATV CALL FCONFIRM CALL FFORMATDO CALL VERIFY_SECTORS JMP FOK ;--------------------------------------------------------- FLOPPY: WRITE/FORMAT TRACK (ACTUAL FUNCTION) FFORMATDO IN DTRACK ;Fetch TRACK NUMBER from 1771 controller CALL DO_PAT_IBM ;Write the IBM pattern to Track Buffer MVI A,0F4H ;WRITE TRACK LXI H, TRACK_BUFFER CALL WRITE_CMD RET ;--------------------------------------------------------- FLOPPY: WRITE/FORMAT WHOLE DISK w/Verify (INTERACTIVE) FFORMATD CALL FCONFIRM ;User to confirm FORMAT Y/N? CALL PUT_NEW_LINE CALL HOME ;Sets DTRACK to 0 JNZ FERR FFD_LP1 CALL PUT_NL_TRACK ;Display the current Track to console & LED CALL FFORMATDO ;Format Track CALL VERIFY_SECTORS CALL ABORT_CHECK IN DTRACK ;Advance to next track OR exit if end of disk CPI 76 JZ F_HOME_RESULT MVI A,53h ;STEP IN CALL DO_DCMD JMP FFD_LP1 ;--------------------------------------------------------- FLOPPY: VERIFY READ/WRITE OF THE SECTORS ON CURRENT TRACK VERIFY_SECTORS: MVI D,01 ;SECTOR NUMBER VS_LP1 LXI H, TRACK_BUFFER MOV A,D OUT DSECTOR MVI A,088h ;Read Sector (wo/ 10mS delay for head load) CALL READ_CMD JNZ VS_ERR ;Compare the read back buffer LXI H, TRACK_BUFFER ;Read Back buffer MVI B,128 ;Sector Length MVI A,0E5H VS_LP2 CMP M ;TEST IT JNZ VS_ERR MOV M,B ;Nuke the buffer as we go INX H DCR B JNZ VS_LP2 MOV A,D ADI 040h ;Convert to letter CALL PUT_CHAR INR D MOV A,D CPI 27 JNZ VS_LP1 RET VS_ERR CALL PRINTI ERR_SECVV: .text "\r\nERROR, SECTOR : \000" IN DSECTOR CALL PUT_BYTE CALL PRINTI .text " DID NOT VERIFY @ \000" CALL PUT_HL CALL PUT_NEW_LINE LXI H, TRACK_BUFFER ;Read Back buffer LXI D, TRACK_BUFFER+080h CALL MEM_DUMP_LP POP H ;Scrap return to calling routine and return to previous call RET PUT_NL_TRACK CALL PUT_NEW_LINE ;Display the current Track to console & LED IN DTRACK CALL PUT_BYTE MVI A,':' CALL PUT_CHAR IN DTRACK SUI 76 DCR A OUT FPLED RET ;--------------------------------------------------------- FLOPPY: TEST READ/WRITE OF ALL TRACKS/SECTORS FTESTD CALL PRINTI .text "\r\nVERIFY WILL OVERWRITE DISK\000" CALL FCONFIRM CALL PUT_NEW_LINE CALL HOME ;Sets DTRACK to 0 JNZ FERR FTD_LP1 CALL PUT_NL_TRACK ;Display the current Track to console & LED CALL TEST_SECTORS ;Test 26 sectors on current track IN DTRACK ;Advance to next track OR exit if end of disk CPI 76 JZ F_HOME_RESULT MVI A,53h ;STEP IN CALL DO_DCMD JMP FTD_LP1 ; ;------------------------------------------; Test 26 sectors on current track TEST_SECTORS MVI D,1 ;D=Sector MOV A,D ;Force a head load by reading first sector OUT DSECTOR LXI H, TRACK_BUFFER MVI A,08Ch ;Read Sector (w/ head load) CALL READ_CMD TEST_SECTORS_LP MVI A,0FFH ;TEST ALL FF'S CALL FILL_WRITEVV JC FFV_ERR MVI A,0H ;TEST ALL 00'S CALL FILL_WRITEVV JC FFV_ERR MVI A,0FH ;TEST ALL 0F'S CALL FILL_WRITEVV JC FFV_ERR MVI A,0AAH ;TEST ALL AA'S CALL FILL_WRITEVV JC FFV_ERR MVI A,0E5H ;TEST ALL E5'S (Default value for Formated Sector) CALL FILL_WRITEVV JC FFV_ERR MOV A,D ADI 040h ;Convert to letter CALL PUT_CHAR CALL ABORT_CHECK INR D MOV A,D CPI 27 JNZ TEST_SECTORS_LP RET ABORT_CHECK CALL GET_CHAR_COUNT RZ CALL GET_CHAR CPI 27 RNZ POP H ;SCRAP RETURN ADDRESS AND GO TO PARENT ROUTINE CALL PRINTI .text "\r\nABORTED\000" RET FFV_ERR LXI H, ERR_SECVV CALL PRINT MOV A,D CALL PUT_HEX POP H RET ;------------------------------------------; Test Current Sector / Track FILL_WRITEVV: LXI H, TRACK_BUFFER ;Fill memory with Test Byte MVI B,128 CALL FILL_HL MOV A,D ;Set Drive with Sector # under test OUT DSECTOR PUSH B PUSH D ;Nuke the read back buffer to ensure actual data is coming from Disk LXI H, TRACK_BUFFER ;Write Buffer LXI D, TRACK_BUFFER + 128 ;Read Back buffer MVI B,128 ;Sector Length WSV_NUKEM MOV A,M ;FETCH BYTE CMA ;NUKE IT STAX D ;Save nuked byte in read buffer INX H INX D DCR B JNZ WSV_NUKEM ;Write the Sector & Read it back LXI H, TRACK_BUFFER MVI A,0A8h ;Write Sector (wo/ 10mS delay for head load) CALL WRITE_CMD JNZ WSV_ERR MVI A,088h ;Read Sector (wo/ 10mS delay for head load) CALL READ_CMD JNZ WSV_ERR ;Compare the read back buffer LXI H, TRACK_BUFFER ;Write Buffer LXI D, TRACK_BUFFER + 128 ;Read Back buffer MVI B,128 ;Sector Length WSV_CMPM LDAX D ;FETCH BYTE CMP M ;TEST IT JNZ WSV_ERR INX H INX D DCR B JNZ WSV_CMPM ORA A ;SUCCESS, CY=0 POP D POP B RET WSV_ERR CALL PRINTI .text "ERROR HL:\000" CALL PUT_HL STC ;FAIL, CY=1 POP D POP B RET ;--------------------------------------------------------- FLOPPY: SECTOR READ FSECREAD MVI A,08Ch ;READ SECTOR (w/ 10mSec Head Load Delay) LXI H, TRACK_BUFFER CALL READ_CMD CALL PRINT_RES CALL PRINT_HL LDA RES ORA A JNZ FERR LXI H,TRACK_BUFFER LXI D,TRACK_BUFFER + 07Fh CALL MEM_DUMP_LP RET ;--------------------------------------------------------- FLOPPY: SECTOR WRITE FSECWRITE CALL FCONFIRM MVI A,0ACh ;WRITE SECTOR (w/ 10mSec Head Load Delay) LXI H, TRACK_BUFFER CALL WRITE_CMD CALL PRINT_RES CALL PRINT_HL RET ;--------------------------------------------------------- FLOPPY: Get a 'Y' confirmation before writting to disk FCONFIRM CALL PRINTI .text "\r\nPLEASE CONFIRM DISK WRITE?\000" CALL GET_CHAR CPI 'Y' RZ ;RETURN IF 'Y' POP H ;ELSE, SCRAP RETURN ADDRESS RET ;AND RETURN TO PREVIOUS CALLING ROUTINE ;--------------------------------------------------------- FLOPPY: Print Result Codes PRINT_RES CALL PRINTI .text " RES:\000" LDA RES CALL PUT_BYTE CALL PUT_SPACE RET PRINT_HL CALL PRINTI .text " HL:\000" LHLD HLWRITE MOV A,H SUI (TRACK_BUFFER / 100H) CALL PUT_BYTE MOV A,L CALL PUT_BYTE CALL PUT_SPACE RET ;---------------------------------------------- FILL MEMORY WITH IBM FORMAT #DEFINE FILLH(xx,yy) MVI B,xx\ MVI A,yy\ CALL FILL_HL DO_PAT_IBM MOV C,A ;TRACK NUMBER GIVEN UPON CALL LXI H, TRACK_BUFFER MVI D,01 ;SECTOR NUMBER MVI E,26 ;SECTOR COUNT ; ~5156 ( 1424h ) RAW BYTES PER TRACK (CRC's counted as 1) ;FILLH(xx,yy) = MVI B,xx \ MVI A,yy \ CALL FILL_HL ie, Count & Value to fill with FILLH(40, 0FFH) FILLH( 6, 000H) FILLH( 1, 0FCH) ;FC (INDEX MARK) FILLH(26, 0FFH) LOOP_SECTOR FILLH( 6, 000H) FILLH( 1, 0FEH) ;FE (ID ADDRESS MARK) MOV A,C ;TRACK# MOV M,A INX H FILLH( 1, 000H) ;Remove following code to NOT skew Sectors ; PUSH H ; MOV L,D ;look up sector number in skew table ; MVI H,( SKEW_TBL / 100H ) ;HIGH ADDR ; MOV A,M ; POP H ;Uncomment following instruction to NOT skew Sectors MOV A,D ;SECTOR# MOV M,A INX H FILLH( 1, 000H) FILLH( 1, 0F7H) ;F7 (CRC) FILLH(11, 0FFH) FILLH( 6, 000H) FILLH( 1, 0FBH) ;FB (DATA ADDRESS MARK) FILLH(128, 0E5H) ;128 BYTES OF SECTOR DATA FILLH( 1, 0F7H) ;F7 (CRC) FILLH(27, 0FFH) INR D ;Increment to next Sector (Modify to skew Sectors) DCR E ;Count down number of Sectors written JNZ LOOP_SECTOR FILLH(0, 0FFH) FILLH(0, 0FFH) RET ;------------------------------------------------------------------- FILL BYTES INTO BUFFER ; INPUT: B = COUNT, A = VALUE ; OUTPUT: BUFFER HAS B# OF (A) BYTES FILL_HL MOV M,A INX H DCR B JNZ FILL_HL RET ;------------------------------------------------------------------- REPORT RESULTS F_HOME_RESULT CALL HOME JNZ FERR FOK: CALL PRINTI ;Display OK .text "\r\nOK\000" RET FERR: STA RES CALL PRINTI ;Display ERROR .text "\r\nERROR: \000" LDA RES CALL PUT_BYTE RET ;----------------------------------------------------------------------------------------------------; FLOPPY XMODEM TRANSFERS ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; FLOPPY XMODEM TRANSFERS FXSERR: CALL PRINTI ;Display Err when input is invalid .text "\r\nERROR, LOGICAL SECTOR NUMBER WILL BE OUT OF RANGE\000" FXMODEM: CALL PRINTI ;Display Err when input is invalid .text "\r\nFLOPPY XMODEM MENU" .text "\r\nU ssss - UPLOAD (WRITE DISK) ssss=Starting Sector" .text "\r\nD ssss cccc - DOWNLOAD (READ DISK) ssss=Starting Sector, cccc=Count of Sectors" .text "\r\n ssss = 0000 for 1st sector on track 0" .text "\r\n cccc = 07D2 (2002) for a whole disk (77 Tracks, 26 Sectors per)" .text "\r\n" .text "\r\n\000" FXMENU_LP: MVI A,':' CALL PUT_CHAR CALL GET_CHAR ;get char CPI 27 ;Branch to Command entered RZ ; <ESC> = Exit CPI '?' ; JZ FXMODEM ; ? = Help ANI 5Fh ;to upper case CPI 'D' ;Branch to Command entered JZ FXMDN ; D = Download to Terminal (Read Disk) D XXXX YYYY Where XXXX is Logicial sector and YYYY is Count of Sectors to send CPI 'U' JZ FXMUP ; U = Upload from Terminal (Write Disk) JMP FXMENU_LP FXMDN CALL SPACE_GET_WORD ;Input Logical Sector (to DE) XCHG SHLD XSUM ;Save to sum up Logical sector + count of sectors SHLD XPOS ;Save position of next read XCHG CALL LOG2PHY ;Set the Physical Track and Sector based on the Logical Sector 0=Sector 1, Track 0 JNC FXSERR ;Sector out of range XCHG SHLD XSECTOR ;Set XSECTOR & XTRACK (16 bit save to two 8 bit variables) CALL SPACE_GET_WORD ;Input # Sectors (Blocks) to Send XCHG SHLD XCOUNT XCHG ;Now test if the read of sectors will extend out of range. LHLD XSUM DAD D ;HL = HL + DE. START_SECTOR = START_SECTOR + SECTOR_COUNT JC FXSERR ;Sector out of range LXI D,0FFFFH DAD D ;HL = HL - 1 XCHG CALL LOG2PHY ;Test Start + Count - 1 <= Valid Track/Sector JNC FXSERR ;Sector out of range CALL XMS_INIT ;Starts the Seq, Sets the CS/CRC format ;Cancelled Transfers will cause a RET FXMDN_LP LHLD XCOUNT ;IF COUNT = 0 THEN EXIT MOV A,H ORA L JZ FXMDN_DONE DCX H ;ELSE, COUNT = COUNT - 1 SHLD XCOUNT ;Future? Check if Drive is already on correct Track LDA XTRACK ;Seek to correct Track (can't be much of a delay if already on correct track) CALL FSEEK LDA XSECTOR ;Read the Sector OUT DSECTOR LXI H, TRACK_BUFFER ; MVI A,088h ;Read Sector (wo/ 10mS delay for head load) MVI A,08Ch ;Read Sector (with 10mS delay for head load) CALL READ_CMD LXI H,TRACK_BUFFER ;Where to Send the Packet from CALL XMS_SEND ;Sends the packet @HL, Resends if NAK ;Cancelled Transfers will cause a RET LHLD XPOS ;Advance to next Logical Sector INX H SHLD XPOS XCHG CALL LOG2PHY ;Set the Physical Track and Sector based on the Logical Sector 0=Sector 1, Track 0 JNC FXSERR ;Sector out of range XCHG SHLD XSECTOR ;Set XSECTOR & XTRACK (16 bit save to two 8 bit variables) JMP FXMDN_LP FXMDN_DONE CALL XMS_EOT ;Send End of Transmission JMP PURGE ;Disk XMODEM FXMUP CALL SPACE_GET_WORD ;Input Logical Sector (to DE) XCHG SHLD XPOS ;Save position of next write XCHG CALL LOG2PHY ;Set the Physical Track and Sector based on the Logical Sector 0=Sector 1, Track 0 JNC FXSERR ;Sector out of range XCHG SHLD XSECTOR ;Set XSECTOR & XTRACK (16 bit save to two 8 bit variables) LXI H,TRACK_BUFFER ;Where to receive data CALL XMR_INIT ;Starts the transfer, Sets the CS/CRC format & Receives first PACKET ;Cancelled Transfers will cause a RET XMU_DISK_LP LDA XTRACK ;Seek to correct Track (can't be much of a delay if already on correct track) CALL FSEEK LXI H,TRACK_BUFFER ;Where to save data LDA XSECTOR ;Read the Sector OUT DSECTOR MVI A,0ACh ;WRITE SECTOR (w/ 10mSec Head Load Delay) CALL WRITE_CMD LHLD XPOS ;Advance to next Logical Sector INX H SHLD XPOS XCHG CALL LOG2PHY ;Set the Physical Track and Sector based on the Logical Sector 0=Sector 1, Track 0 JNC FXSERR ;Sector out of range XCHG SHLD XSECTOR ;Set XSECTOR & XTRACK (16 bit save to two 8 bit variables) LXI H,TRACK_BUFFER ;Where to receive data CALL XMR_RECV ;Receives the next packet @HL, Resends if NAK ;Cancelled Transfers will cause a RET JC XMU_DISK_LP ;Jump until EOT Received JMP PURGE ;--------------------------------------------------------------------------------------------------------------------- ;Logical Sector to Physical Sector and Track # ;0=Track 0 : Sector 1 ;1=0:2, 25=0:26, 26=1:1, 2001=77:26 (Last logical Sector) ;In: DE = Logical Sector 0 to 2001 ;Out: D = Track (0-76) ; E = Sector (1-26) ; CY = Set for Valid Log Sec ;Uses: A ;--------------------------------------------------------------------------------------------------------------------- LOG2PHY MOV A,D ANI 0F8H RNZ ;Return with CY clear PUSH B MVI B,0 ;Track=0 L2LP PUSH D ;Save DE before subtracting 26 sectors per track MOV A,E ;Subtrack 26 from E SUI 26 MOV E,A JNC L2PNT ;If no borrow occurs, then set track DCR D ;Decrement D JM L2PSS ;If negative, Set Sector L2PNT POP PSW ;Scrap saved DE, accept DE as it's still positive INR B ;Else, Advance Track JMP L2LP L2PSS POP D INR E MOV A,B MOV D,A CPI 77 ;Test for invalid TRACK# (happens POP B ;Return CY set for valid Logical Sector RET ;----------------------------------------------------------------------------------------------------; DISASSEMBLER ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; DISASSEMBLER DISASM CALL PUT_HL ;Print Address ***CAUTION**** This routine has 3 tables that must NOT cross page boundaries. CALL PRINTI .text " \000" MOV C,M PUSH H CALL DA_LOOKUP ;Print Mnemonic code POP H ORA A ;Test if there are any operands to print JZ DA_NOOP ;Jump if NO operands DCR A JNZ DA_N1OP ;Jump if 2 operands (actually, if NOT 1 operand) INX H MOV A,M ;Print Byte CALL PUT_BYTE JMP DA_NOOP DA_N1OP DCR A JNZ DA_NOOP INX H ;Print Word (high/low) MOV B,M INX H MOV A,M CALL PUT_BYTE MOV A,B CALL PUT_BYTE DA_NOOP CALL PUT_NEW_LINE INX H RET ;Print Operand for Machine Code in C DA_LOOKUP LXI H, TBL_1A MVI A,0FFH ;Bit Mast (Mask no bits) LXI D,5 ;DE=LEN of table entry CALL LS_SEARCH ;Search for commands without embedded codes or extra operands. JZ DA_FOUND MOV A,C ;Fetch Code ANI 0C0H CPI 040H ;Test for MOV code JZ DA_MOV MVI A,0CFH ;Mask out register pairs CALL LS_SEARCH ;Search for 1C commands (Reg Pairs) JZ DA_FOUND_1C CALL LS_SEARCH ;Search for 3C command (LXI Reg Pairs,Immediate) JZ DA_FOUND_3C MVI A,0F8H ;Mask out SSS register CALL LS_SEARCH ;Search for 1B commands (Source Register) JZ DA_FOUND_1B MVI A,0C7H ;Mask out DDD register CALL LS_SEARCH ;Search for 1B commands (Source Register) JZ DA_FOUND_1D CPI 006H ;Search for MVI command JZ DA_FOUND_2B CPI 0C7H ;Search for RST command JZ DA_FOUND_1R MVI A,0EFH CALL LS_SEARCH ;Search for 1E commands (STAX or LDAX Reg Pairs) JZ DA_FOUND_1C MVI A,0FFH CALL LS_SEARCH ;Search for 2A commands (Acc Immediate functions) JZ DA_FOUND_2A CALL LS_SEARCH ;Search for 3C commands (LDA,STA,LHLD,SHLD) JZ DA_FOUND_3D MVI A,0C7H ;Mask out Condition Code & LSB MVI E,2 ;DE=LEN of table entry CALL LS_SEARCH ;Search for 3B commands (Jump / Call Commands) JZ DA_FOUND_3B DA_DB CALL PRINTI ;When all searchs fail, print byte as a DB .text "DB \000" MOV A,C CALL PUT_BYTE XRA A RET DA_FOUND_3D CALL DA_FOUND ;Print opcode CALL PUT_SPACE MVI A,2 ;Return to print 16 bit Memory operand RET DA_FOUND_2A CALL DA_FOUND ;Print opcode CALL PUT_SPACE MVI A,1 ;Return to print 8 bit immediate Operand RET DA_FOUND_3B INX H MOV A,M ;Print First letter of Op Code (J,C or R) CALL PUT_CHAR MOV A,C ;Fetch Code for DDD RRC RRC LXI H, TBL_CC ANI 0EH ;Print 2 character Condition Code ADD L MOV L,A MOV A,M CALL PUT_CHAR INX H MOV A,M CALL PUT_CHAR CALL PRINTI .text " \000" DAF_3B_RET MOV A,C ;Codes that end in 100 or 010 result with 2 Operands RRC ;This allows address to be printed for JMP's and CALL's ORA C ;but not RET's ANI 2 RET TBL_CC .text "NZZ NCC POPEP M " DA_FOUND_1R CALL PRINTI .text "RST \000" MOV A,C RRC RRC RRC ANI 7 CALL PUT_HEX XRA A RET DA_FOUND_2B CALL PRINTI .text "MVI \000" CALL DA_PUT_DDD CALL PRINTI .text ",\000" MVI A,1 RET DA_FOUND_1D CALL DA_FOUND CALL PUT_SPACE JMP DA_PUT_DDD DA_FOUND_1B CALL DA_FOUND CALL PUT_SPACE JMP DA_PUT_SSS DA_FOUND_3C CALL DA_FOUND_1C CALL PRINTI .text ",\000" MVI A,2 RET DA_FOUND_1C CALL DA_FOUND ;Print the opcode CALL PUT_SPACE CALL DA_PUT_REGPAIR XRA A RET DA_FOUND MOV B,E ;Prints Opcode (no operands) DCR B DAF_LP INX H MOV A,M ORA A RZ CALL PUT_CHAR DCR B JNZ DAF_LP XRA A RET DA_MOV CALL PRINTI ;Prints MOV Opcode with 2 operands DDD, SSS .text "MOV \000" CALL DA_PUT_DDD CALL PRINTI .text ",\000" DA_PUT_SSS MOV A,C ;Fetch Code for SSS DA_PUT_SSSDDD LXI H, TBL_DDDSSS ANI 07H ADD L MOV L,A MOV A,M CALL PUT_CHAR XRA A RET DA_PUT_DDD MOV A,C ;Fetch Code for DDD RRC RRC RRC JMP DA_PUT_SSSDDD TBL_DDDSSS .text "BCDEHLMA" DA_PUT_REGPAIR MOV A,C ;Fetch Code for Reg Pair RRC RRC RRC LXI H, TBL_REGPAIR ANI 0EH CPI 0EH ;Test for PSW Reg Pair JNZ DAPR_OK MVI A,9 JMP DAPR_OK2 DAPR_OK ANI 6H DAPR_OK2 ADD L MOV L,A JMP PRINT ;Print returns with A=00 ;CALL PRINT ;XRA A ;RET TBL_REGPAIR .text "B\000" .text "D\000" .text "H\000" .text "SP\000" .text "PSW\000" LS_SEARCH ANA C ;Fetch Code (AND with bit mask) MOV B,M ;Count of Elements INX H LS_LP CMP M RZ DAD D DCR B JNZ LS_LP DCR B ;RETURN WITH Z=0 RET TBL_1A .DB 17 ;COUNT OF TABLE ELEMENTS .DB 0EBH .text "XCHG" .DB 0E3H .text "XTHL" .DB 0F9H .text "SPHL" .DB 0E9H .text "PCHL" .DB 007H .text "RLC " .DB 00FH .text "RRC " .DB 017H .text "RAL " .DB 01FH .text "RAR " .DB 02FH .text "CMA " .DB 037H .text "STC " .DB 03FH .text "CMC " .DB 027H .text "DAA " .DB 0FBH .text "EI " .DB 0F3H .text "DI " .DB 000H .text "NOP " .DB 076H .text "HLT " .DB 0C9H .text "RET " TBL_1C .DB 5 ;COUNT OF TABLE ELEMENTS .DB 0C5H .text "PUSH" .DB 0C1H .text "POP " .DB 003H .text "INX " .DB 00BH .text "DCX " .DB 009H .text "DAD " TBL_3C .DB 1 ;COUNT OF TABLE ELEMENTS .DB 001H .text "LXI " TBL_1B .DB 8 ;COUNT OF TABLE ELEMENTS .DB 080H .text "ADD " .DB 088H .text "ADC " .DB 090H .text "SUB " .DB 098H .text "SBB " .DB 0A0H .text "ANA " .DB 0A8H .text "XRA " .DB 0B0H .text "ORA " .DB 0B8H .text "CMP " TBL_1D .DB 2 ;COUNT OF TABLE ELEMENTS .DB 004H .text "INR " .DB 005H .text "DCR " TBL_1E .DB 2 ;COUNT OF TABLE ELEMENTS .DB 002H .text "STAX" .DB 00AH .text "LDAX" TBL_2A .DB 10 ;COUNT OF TABLE ELEMENTS .DB 0C6H .text "ADI " .DB 0CEH .text "ACI " .DB 0D6H .text "SUI " .DB 0DEH .text "SBI " .DB 0E6H .text "ANI " .DB 0EEH .text "XRI " .DB 0F6H .text "ORI " .DB 0FEH .text "CPI " .DB 0DBH .text "IN " .DB 0D3H .text "OUT " TBL_3D .DB 6 ;COUNT OF TABLE ELEMENTS .DB 032H .text "STA " .DB 03AH .text "LDA " .DB 022H .text "SHLD" .DB 02AH .text "LHLD" .DB 0C3H .text "JMP " .DB 0CDH .text "CALL" TBL_3B .DB 3 ;COUNT OF TABLE ELEMENTS .DB 0C2H .text "J" .DB 0C4H .text "C" .DB 0C0H .text "R" ;----------------------------------------------------------------------------------------------------; CONSOLE BIOS ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; CONSOLE BIOS CSTAT .EQU 0 ;CONSOLE STATUS PORT. MSB=RX DATA READY, LSB=TX BUFFER EMPTY CDATA .EQU 1 ;CONSOLE DATA PORT. ;=============================================== ;GET_CHAR_COUNT -- Get count of chars coming in from Console (1 OR 0) ;----------------------------------------------- GET_CHAR_COUNT: IN CSTAT RLC ;TEST FOR RX DATA CMA ANI 1 RET ;=============================================== ;GET_CHAR -- Get a char from the console ;----------------------------------------------- GET_CHAR: LDA ECHO_ON ORA A JZ GET_CHAR_NE GET_CHAR_LP IN CSTAT RLC ;TEST FOR RX DATA JC GET_CHAR_LP IN CDATA CPI ' ' ;Do not echo control chars RM ;RET ;ECHO THE CHAR ;=============================================== ;PUT_CHAR -- Output a character to the console ;----------------------------------------------- PUT_CHAR: PUSH PSW PC_LP IN CSTAT RRC ;TEST FOR TX DATA EMPTY JC PC_LP POP PSW OUT CDATA RET ;=============================================== ;GET_CHAR -- Get a char from the console NO ECHO ;----------------------------------------------- GET_CHAR_NE: IN CSTAT RLC ;TEST FOR RX DATA JC GET_CHAR_NE IN CDATA RET ;=============================================== ;TIMED1_GETCHAR - Gets a character within 1 second ; ;pre: nothing ;post: Carry Set = No Char, Time Out ; Carry Clear, A = Char ;----------------------------------------------- TIMED1_GETCHAR MVI A,1 ;=============================================== ;TIMED_GETCHAR - Gets a character within a time limit ; ;pre: A contains # of seconds to wait before returning ;post: Carry Set & Zero Set = No Char, Time Out ; Carry Clear, A = Char ;----------------------------------------------- TIMED_GETCHAR PUSH D PUSH B MOV D,A ;MVI C,0 ;B,C=Loop Count down until timeout TGC_LP1 MVI B,200 TGC_LP2 IN CSTAT ;10 RLC ;4 TEST FOR RX DATA JNC TGC_DO ;10 DCR C ;5 JNZ TGC_LP2 ;10 ;39 Cycles Loop time. 39*256*.5 ~= 5 mSec DCR B JNZ TGC_LP2 DCR D JNZ TGC_LP1 STC ;SET CARRY TO INDICATE TIME OUT ;MVI A,0 JMP TGC_RET TGC_DO IN CDATA TGC_RET POP B POP D RET ;=============================================== ;PURGE - Clears all in coming bytes until the line is clear for a full 2 seconds ;----------------------------------------------- PURGE MVI A,2 ;2 seconds for time out CALL TIMED_GETCHAR JNC PURGE RET ;----------------------------------------------------------------------------------------------------; FLOPPY DISK BIOS ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; FLOPPY DISK BIOS DWAIT .EQU 0FCH DSTAT .EQU 0F8H DCMD .EQU 0F8H DTRACK .EQU 0F9H DSECTOR .EQU 0FAH DDATA .EQU 0FBH ;------------------------------------------------------------------- WRITE COMMAND ;Enter: HL= Ptr to Memory block to write ; A = F4H ;WRITE TRACK (FORMAT) (~5156 bytes will be read from memory and written to disk) ; A = ACh -Write Sector (w/ 10mS delay for head load) (128 bytes read & written) ; A = A8h -Write Sector (wo/ 10mS delay for head load) WRITE_CMD: OUT DCMD ;Maximum allowed Machine cycles = 64 to service a Data Request (DRQ) FT_LP IN DWAIT ;10 Puts CPU in WAIT State until INTRQ or DRQ ORA A ;4 JP FT_DONE ;10 JUMP WHEN INTRQ MOV A,M ;7 GET BYTE OUT DDATA ;10 SEND BYTE TO WRITE TO DISK INX H ;5 JMP FT_LP ;10 Total=56 cycles in loop FT_DONE SHLD HLWRITE IN DSTAT ;READ STAT ANI 0FDH ;MASK NON ERR BITS STA RES RET ;------------------------------------------------------------------- READ COMMAND ;Enter: HL= Ptr to Memory block to save read data ; A = E4h -Read Track (Synchronized) ; A = E4h -Read Track (Non-Synchronized) ; A = 8Ch -Read Sector (w/ 10mS delay for head load) ; A = 88h -Read Sector (wo/ 10mS delay for head load) READ_CMD: OUT DCMD ;Maximum allowed Machine cycles = 64 to service a Data Request (DRQ) LP_RT IN DWAIT ;10 Puts CPU in WAIT State until INTRQ or DRQ ORA A ;4 JP RT_DONE ;10 JUMP WHEN INTRQ IN DDATA ;10 GET BYTE TO READ FROM DISK MOV M,A ;7 SAVE BYTE INX H ;5 JMP LP_RT ;10 Total=56 cycles in loop RT_DONE SHLD HLWRITE IN DSTAT ;READ STAT ANI 0FDH ;MASK NON ERR BITS STA RES RET ;------------------------------------------------------------------- HOME HEAD TO TRACK 00 ; INPUT: NOTHING ; OUTPUT: A = STATUS ; Z = 1 OK HOME CALL FDC_RESET ;CLEAR ANY PENDING COMMAND MVI A,3 ;RESTORE TO TRACK 0 CALL DO_DCMD RET ;------------------------------------------------------------------- SEEK HEAD TO TRACK (A) FSEEK OUT DDATA ;SEEK TO TRACK (A) MVI A,13h ;SEEK CMD CALL DO_DCMD RET ;------------------------------------------------------------------- OUTPUT COMMAND TO FDC ;Enter: A = Command to send to FD1771 Floppy Drive Controller ; DO_DCMD OUT DCMD ;ISSUE COMMAND IN DWAIT ;This will put the cpu in DWAIT state until DRQ or INTRQ become high ORA A ;Only INTRQ* is read on Bit7. So JM branches if NOT INTRQ event IN DSTAT ;Fetch status JM DDC_ERR ;ERROR IF DRQ HAPPENS INSTEAD OF INTRQ XRI 4 ;INVERT TRACK00 STATUS TO MAKE A "NOT TRACK00 ERROR" ANI 95H ;RETURN WITH STATUS RET DDC_ERR ORI 22H ;Flag data request error (FDC should not be requesting data) RET ;------------------------------------------------------------------- RESET FDC FDC_RESET MVI A,0D0H ;CLEAR ANY PENDING COMMAND OUT DCMD FRLP IN DSTAT RRC JC FRLP ;DWAIT FOR NOT BUSY RET .ORG (($ + 0FFH) & 0FF00H) TRACK_BUFFER .BLOCK 1500H ; 145Eh ~ 1469h .end ;----------------------------------------------------------------------------------------------------; INSTRUCTION LIST REFERENCE ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<; ;----------------------------------------------------------------------------------------------------; ;DATA TRANSFER GROUP ;'Mnem. 'Description 'Notes ' ;'----------+----------------------------+---------------------' ; MOV r1,r2 | r1 <- r2 |r = A,B,C,D,E,H,L ; MOV r,M | r <- (HL) ; MOV M,r | (HL) <- r ; HLT | HALT ; MVI r,d | r <- d, Move Immediate data ; MVI M | (HL) <- d, Immediate data ; INR r | r <- r+1 ; DCR r | r <- r-1 ; INR M | (HL) <- (HL)+1 ; DCR M | (HL) <- (HL)-1 ; ADD r | A <- A+r ; ADC r | A <- A+r+CY |Add with Carry ; SUB r | A <- A-r ; SBB r | A <- A-r-CY |Subtract with Borrow ; ANA r | A <- A AND r ; XRA r | A <- A XOR r ; ORA r | A <- A OR r ; CMP r | A-r |Compare ; ADD M | A <- A+(HL) ; ADC M | ; SUB M | ; SBB M | ; ANA M | ; XRA M | ; ORA M | ; CMP M | ; ADI d | A <- A+d, ADD Immediate data ; ACI d | ; SUI d | ; SBI d | ; ANI d | ; XRI d | ; ORI d | ; CPI d | ; RLC | Rotate A Left, CY<-MSB ; RRC | Rotate A Right, CY<-LSB ; RAL | Rotate A Left through Carry ; RAR | Rotate A Right through Carry ; JMP addr | Jump Address ; JC addr | Jump on Carry ; JNC addr | Jump on NOT Cary ; JZ addr | Jump on ZERO ; JNZ addr | Jump on NOT ZERO ; JP addr | Jump on Positive (MSB=0) ; JM addr | Jump on Minus (MSB=1) ; JPE addr | Jump on Parity Even (Parity bit =1) ; JPO addr | Jump on Parity Odd (Parity bit =0) ; CALL addr | Call subroutine ; CC addr ; CNC addr ; CZ addr ; CNZ addr ; CP addr ; CM addr ; CPE addr ; CPO addr ; RET | Return from subroutine ; RC ; RNC ; RZ ; RNZ ; RP ; RM ; RPE ; RPO ; RST n | Restart to Vector n | n=0,1,2,3,4,5,6,7 ; IN p | A <- Port p, Input ; OUT p | Port p <- A, Output ; LXI B,dd | BC <- dd, Load Immediate data, 16 bit to Register Pair ; LXI D,dd | DE <- dd ; LXI H,dd | HL <- dd ; LXI SP,dd | SP <- dd ; PUSH B | PUSH BC register pair to STACK ; PUSH D | PUSH DE register pair to STACK ; PUSH H | PUSH HL register pair to STACK ; PUSH PSW | PUSH A,Flags register pair to STACK ; POP B | POP BC register pair from STACK ; POP D | POP DE register pair from STACK ; POP H | POP HL register pair from STACK ; POP PSW | POP A,Flags register pair from STACK ; STA addr | (addr) <- A, Store A Direct ; LDA addr | A <- (addr), Load A Direct ; XCHG | Exchange HL <> DE ; XTHL | Exchange HL <> (SP), Exchange HL with Top of Stack ; SPHL | SP <- HL, Move HL to SP ; PCHL | PC <- HL, Move HL to PC ; DAD B | HL <- HL+BC, Add 16 bit register pairs ; DAD D | HL <- HL+DE, Add 16 bit register pairs ; DAD H | HL <- HL+HL, Add 16 bit register pairs ; DAD SP | HL <- HL+SP, Add 16 bit register pairs ; STAX B | (BC) <- A, Store A Indirect ; STAX D | (DE) <- A, Store A Indirect ; LDAX B | A <- (BC), Load A Indirect ; LDAX D | A <- (DE), Load A Indirect ; INX B | BC <- BC+1, Increment 16 bit register pair ; INX D | DE <- DE+1, Increment 16 bit register pair ; INX H | HL <- HL+1, Increment 16 bit register pair ; INX SP | SP <- SP+1, Increment 16 bit register ; DCX B | BC <- BC-1, Decrement 16 bit register pair ; DCX D | DE <- DE-1, Decrement 16 bit register pair ; DCX H | HL <- HL-1, Decrement 16 bit register pair ; DCX SP | SP <- SP-1, Decrement 16 bit register ; CMA | A <- /A, Complement Accumulator ; STC | Set Carry ; CMC | Complement Carry ; DAA | Decimal Adjust Accumulator ; SHLD addr | (addr) <- HL, Store HL Direct ; LHLD addr | HL <- (addr), Load HL Direct ; EI | Enable Interrupts ; DI | Disable Interrupts ; NOP | No Op