[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [N8VEM-S100:1495] New/Old Project (Altair restoration)



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