8085 assembly question - Page 1
Forum section: electronics / general

author: ChristofferB
author_rank: Frequent Contributor
timestamp: April 15, 2016, 02:46:54 pm
content: Hi! So I'm in the midst of building a rack-mounted modular 8085 computer.While I've done some assembly programming for the Z80, and a bit x86, there's still some things that aren't clear.I want to make a small monitor program, like the turnkey altair 8800 had:-Communicates with a terminal (or teletype) via serial-has a few commands, like: examine memory, change memory, jump to address.that's it.How would you attack this task? I'm pretty green at assembly, one of the reasons I'm doing this project, but something like (very pseudocode):-initialize UART-display prompt (send ">" to uart)-loop until character received (check uart flag for that)-test if received character is equal to one of the reseved characters for examine, jump)-if examine call examine subroutine, if jump call jump routineexamine/edit routine:- send "L?" to UART- wait for ascii byte to be received (check uart flag for that)- let that be low byte of address, saved to some location in RAM- send "H?" to UART- wait for ascii byte to be received (check uart flag for that)- let that be high byte of address, saved to some location +1 in RAM- send address HL, conv. to ascii to UART- send data at address HL, converted to ascii to UART- loop wait for UART input.if "space", increment address HL and print again- if a digit, save that, wait for the next, and change RAM in addr HL to new value- if any other key, go back to promptJump routine is easier: receive 2 bytes, jmp to address and run from there.This is grossly simplified, from an .asm point of view, just thought i'd shorten it to reasonable chunks.Here's my main issue: Almost exactly this was achieved on the Altair turnkey monitor, in 256 bytes.I can't see how this is doable without a binary-> ascii lookup table routine.that'd take up half the 256 bytes.Has anyone ever written a 8 bit monitor, or something similar? Most (x86) assembler info is either very high-level, or very low-level.Here's the turnkey-prom monitor documentation:http://bitsavers.trailing-edge.com/pdf/mits/8800b_Turnkey_PROM_Monitor_Aug77.pdfThanks in advance!

author: MrSlack
author_rank: Frequent Contributor
timestamp: April 15, 2016, 02:58:08 pm
content: Converting binary ASCII to binary is easy without a LUT. I'm giving you it the other way round as it's more useful to think of it this way first. Pseudo code, assuming X is a byte and there are 8 binary ASCII digits.X = 0next: C = readchar()If C == '0' X<<1If C = '1' { X &= 1; X << 1; }If not done goto nextTo get it the other way it's pretty much the same in reverse. Shift, and, test, print 8 times depending on flags (remember the zero flag after a compare/test)Clearly define all your routines and calling conventions I.e what registers are used where and when and you can get that in 256 bytes easy. 8085 has segments if I remember which is a bit of a dick and slightly more verbose.If in doubt steal C's standard library - in assembly it's tiny

author: rstofer
author_rank: Super Contributor
timestamp: April 15, 2016, 03:31:34 pm
content: Great project! A simple monitor was the first bit of code I wrote for any 8085 project and I did several. Mine would fit in a 1kB EEPROM.Here is a rather complete monitor:https://github.com/jefftranter/8080/tree/master/asm/monitorI would look through the code for ideas and possibly delete some of the stuff that doesn't apply. Or, leave it alone... It apparently takes more the 1kB because he places it 2k down from the end of memory which, in the listing, is just 24k. I assume he enters the monitor with the console switches because the CPU will always start at 0x0000h.What to do about that? Well, the common way was to bank the RAM and the EPROM such that at reset, the EEPROM occupied address 0x0000h and RAM didn't respond to CE (chip enable). The EPROM would have a jump instruction to the actual address in high memory for the next instruction which would immediately map the EPROM out of low memory and map the RAM in (just diddling around with the CE signals).You really don't want to have to start the machine with toggle switches to 0xFC00 (assuming a 1k monitor) so banking is the way to get around it.These days, you can buy a 32kx8 RAM chip (maybe even a 64kx8) so I imagine you will build your own memory setup. Just work through the banking issue. It's pretty simple. You don't even need an IO port. You can use part of the address and the RD signal to change the banking flip-flop when a high address is first read. The flip-flop is reset at startup and set when the first high address instruction is read. It stays set forever (until the board is reset).If you implement something like CP/M 2.2 then you have to do a similar thing to get the first JMP COLDSTART to work. Then, instead of a monitor, you place the BIOS code in high RAM.

author: ChristofferB
author_rank: Frequent Contributor
timestamp: April 15, 2016, 04:06:43 pm
content: QuoteSo in a byte, for every zero element, you do nothing, and for every one element, you AND the element with 1? I'll have to try that in BASIC to visualize it, but great to know there's a mathematical way of doing it! thanks a bunch!The 8085 is not segmented, that's the 8086/8088 and newer. One of my reasons for choosing the 8085.QuoteGreat! I'll dig through that and use what I can!I'm planning on a rather small memory at first, 4K ram/8K rom, but then expandable to the full 64K.Banking might be a good idea, or just edit the jumps and memory transfers to get around it? If you don't NEED to start ram at 0000H (CP/M does need that.)

author: obiwanjacobi
author_rank: Super Contributor
timestamp: April 15, 2016, 04:21:24 pm
content: I am currently writing one in C but I am planning on doing one in Z80 assembly as well.My system has a Z80 as a CPU but it also has a PSoC-5 as a System Controller. There is no ROM so at startup the system controller resets the Z80 until it is released by a command (over serial). This monitor in C is inside the PSoC.I have chosen to wait for a new-line before I dispatch the command. The received bytes are stored in a ring buffer until the new line is received. Then a command parser will parse the first characters until a space is encountered. That string is searched in a lookup table and converted into a command Id. There is a command structure that gets filled with the text and the command id and dispatched to specific command handler functions (switch). Each function can optionally parse additional parameters from the received characters and perform some sort of operation. There is access to the console for generating output.I have commands to manipulate the RAM (DMA), fill, read and write. Memory-write allows you to send a file (as binary) and that will be put into the RAM at the specified address.I also have some commands to change the clock frequency for the Z80 that are managed by the system controller. And finally a command to take the Z80 out of reset and let it run.Another way of organizing this could be to build a state machine that reads one character at a time from the serial input and go to the next state on each recognized character. At one point a complete operation is spelled out and additional states can be added for its parameters. Care must be taken with optional parameters. This could probably be very short code but might not be so clear to read (back)...

author: ChristofferB
author_rank: Frequent Contributor
timestamp: April 15, 2016, 04:27:53 pm
content: Sounds like a cool project!QuoteSee that's what I thought, but I'd hoped there might exist a more straightforward/easily-readable method.

author: MrSlack
author_rank: Frequent Contributor
timestamp: April 15, 2016, 04:34:03 pm
content: Look at FORTH and its execution model as well. That is tiny enough to embed an interpreter in that 256 bytes with possibly enough compressed threaded code to be an interpreter for a monitor.

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: April 15, 2016, 04:35:41 pm
content: Quote from: ChristofferB on April 15, 2016, 02:46:54 pmAs I'm sure you're aware, the 8085 instruction set is a subset of the Z80 set. The Z80 mnemonics are different, and it has bit manipulation, block move, and byte search instructions, and IX/IY index registers the 8085 doesn't have, but otherwise if you've done Z80 assembly programming you shouldn't find it hard to adapt to the 8085.

author: westfw
author_rank: Super Contributor
timestamp: April 15, 2016, 04:38:14 pm
content: QuoteThere were some clever code snippets on 8080/etc for converting ascii->number->ascii using the BCD math instructions (AAA and etc)This turns up after a brief search:Quote

author: obiwanjacobi
author_rank: Super Contributor
timestamp: April 15, 2016, 05:05:06 pm
content: See end of the page, starts at main_loophttp://www.vaxman.de/projects/tiny_z80/

author: westfw
author_rank: Super Contributor
timestamp: April 15, 2016, 05:39:46 pm
content: BTW, I'd recommend reading in an entire line of text (with editing) rather than having immediate response to each character.QuoteI don't think that the editing will end up using much more space than your intermediate prompts...

author: rstofer
author_rank: Super Contributor
timestamp: April 16, 2016, 01:49:32 am
content: Quote from: ChristofferB on April 15, 2016, 04:06:43 pmSure, you can put a small bit of EPROM at 0x0000 as long as you don't plan to run CP/M. There's no reason not too.Once you start messing around with the memory address, it's pretty easy to map whatever you want wherever you want to put it. Some 8080 projects had multiple 64k banks with a common 1 or 2k at the top. I haven't done that myself but I could see putting CP/M BIOS up high in shared RAM and banking several user pages in lower memory. It just never came up.A few years back, I bought a Zilog eZ180 board and I built a daughter card that holds a compact flash device and a couple of FTDI serial->USB chips. CP/M rips when it runs at 50 MHz! I implemented 16 drives of 8 MB each. That's a TON of disk space for CP/M kinds of things!

author: Rasz
author_rank: Super Contributor
timestamp: April 16, 2016, 01:58:10 am
content: this might come in handyhttp://www.s100computers.com/Software%20Index%20Page.htm

author: ebastler
author_rank: Super Contributor
timestamp: April 16, 2016, 04:37:33 am
content: Quote from: westfw on April 15, 2016, 05:39:46 pmAnother clear vote for reading an entire line first (with at least simple "backspace" editing). Interpret the line once it has been terminated by the "return" key. Much more user-friendly because it allows you to correct the occasional typo!

author: ChristofferB
author_rank: Frequent Contributor
timestamp: April 16, 2016, 12:55:42 pm
content: Handling an entire line of text seems smarter in most respects, That's the plan, then.But doesn't that make the recognition of commands more difficult? you'd still need to match them character for character.But again, if I make every command one letter, it won't be a problem.

author: westfw
author_rank: Super Contributor
timestamp: April 17, 2016, 12:52:13 am
content: QuoteNah. For equal commands, it means fetching a character from a buffer, vs fetching it from a uart. Equal complexity.QuoteI don't think it's realistic to expect to be able to write a 256byte monitor without a lot of experience.http://www.autometer.de/unix4fun/z80pack/ftp/altair/turnmon.prn(heh. Octal like a 8080 should be!)

author: ChristofferB
author_rank: Frequent Contributor
timestamp: April 17, 2016, 01:53:44 pm
content: I don't think so either. It doesn't matter too much, sizewise. I'm not limited to 1702 eproms, thank god.Actually, I've begun modifying the altair 8800 turnkey monitor. It seems that the ascii to actual value becomes easier with octal, too. It's also a good base to add more commands to - and the 8080 code runs fine on a 8085.If I can edit the memory ranges, IO ports etc. I should even be able to run most altair software, like 4/8K basic and altair dos.I've also decided to make an actual turnkey card for my computer, featuring both a serial port and a 8K eprom (so much for my quest for a small program, but I have a giant stock of 2764's).Here's the schematic, if anyone's interested:edit: added updates schematic

author: newbrain
author_rank: Super Contributor
timestamp: April 18, 2016, 07:00:47 pm
content: Quote from: MrSlack on April 15, 2016, 04:34:03 pmYesGo Forth!I also wrote quite many monitors for 6502, 68HC11 and the like (still have a 6809 that I'll sooner or later build a board for(th)...), but then I discovered the simpleness and beauty of this underdog language.An ANS forth can be written in a very limited space, and if you use one of the classic implementations (direct or indirect threaded) you can write only the very core routines in assembler and most of the rest directly in forth (when it's working, you can optimize...).The language is easy to learn (especially if you had a real HP as first calculator) blazing fast for an interpreted, interactive, one, and powerful enough to write real programs.At the same time it's very close to metal and easily replaces a monitor.There's still plenty of resources on the net, including the standard and many implementation to learn from (but don't look at gforth to start, it's definitely good but quite complex).

author: rstofer
author_rank: Super Contributor
timestamp: April 18, 2016, 09:08:18 pm
content: Quote from: newbrain on April 18, 2016, 07:00:47 pmMANY years ago (probably around '80), I was writing code to hang hard drives on just about anything. One day I visited the controller manufacturer and they showed me their test setup. It was all built around Forth because the bottom up design of the code allowed them to easily write any kind of high level test they wanted based on that lower level code that was already known to work. I thought it was a pretty clever solution!

author: MrSlack
author_rank: Frequent Contributor
timestamp: April 19, 2016, 08:27:51 am
content: There is a canned 8085 FORTH here:http://www.strangegizmo.com/products/mforth/source/Worth a read. Let me know if you have any questions: I've built a couple of SBCs and FORTHs in the dark ages on Z80 and 68k.Also worth reading "The Computer Journal" which is a publication issued from 1983-1998 about small usually homebrew computers:https://archive.org/details/the-computer-journalThe canonical series of articles on FORTH implementation on small systems and how they all work is here too:http://www.bradrodriguez.com/papers/(see Moving Forth series)

author: westfw
author_rank: Super Contributor
timestamp: April 19, 2016, 09:57:01 am
content: QuoteThat's a little depressing :-( Since we started out talking about 256byte monitors...(Most Forth implementations are likely to include a much more complete set of Forth words than are truly necessary for either a pure monitor, or a forth implementation that can compile the rest of the needed words.http://amforth.sourceforge.net/is nicely broken into little pieces, and looks like it will run in as little as 2k (on Atmel AVR8), but ... I find the documentation especially confusing :-( )

author: MrSlack
author_rank: Frequent Contributor
timestamp: April 19, 2016, 10:11:58 am
content: 512 bytes is enoughYour monitor wouldn't have a FORTH compiler built in, just the runtime as a chunk of DW's at the end. You don't need much RAM for that. Probably 256 bytes. The core FORTH assembly can be crammed in under 256 bytes on Z80. It's basically NEXT, a few small assembly routines for IO, configuring the SIO, stack manipulation and arithmetic. You can then of course decide to either use this to bootstrap more FORTH words or use it to run something else which is the marvelous thing about FORTH: extensibility.A few months down the line: hey guys, it's running a full object system.

author: westfw
author_rank: Super Contributor
timestamp: April 19, 2016, 10:39:40 am
content: QuoteYou have to have enough to interpret/compile new words (I'd call that a compiler, but that's probably not quite right), or you can't do the easy "bootstrap more words." (I guess you could add them as a binary blob, but that would be cheating.) And of course it would be helpful if you already had enough of the standard words that you didn't have to define them first... I don't think 512bytes would be enough.It is unfortunate (?) that microcontrollers and microcomputers have opposite memory dynamics. Microcontrollers have lots of Flash/ROM but not much RAM, so the tendency is to put a "big" Forth in ROM. The 8080 in the OP probably has "lots" of RAM but less flash, making the "add words as you need them" option more attractive. ("amforth" actually burns new words in flash, but I don't think it makes any efforts to optimize that for the limited write-cycles that are allowed.)

author: MrSlack
author_rank: Frequent Contributor
timestamp: April 19, 2016, 10:49:36 am
content: You don't need the compiler or interpreter side of things to run FORTH code. That's entirely optional believe it or not. You can use assembly macros to just call the native functions using direct threading. That's how you bootstrap a FORTH:Code:sqr: dw dup ; points to stack dupdw times ; points to stack timesjmp next ; call NEXTSQR in 16 bit direct threaded tends to land at about 9 bytes. Not bad.

author: westfw
author_rank: Super Contributor
timestamp: April 19, 2016, 11:00:04 am
content: Yes, I understand that. But didn't you imply that the 512byte forth was going to be able to add words to itself? Or were you just proposing that additional words be added to the source (via assembly macros, as you say), reassembled, and reloaded (into ever bigger PROM)as time went on? (until it reached the point where it COULD add words to itself...)Does Forth normally include a way to add binary blobs to the dictionary? I didn't think so, but I don't see why it would be impossible, either.

author: MrSlack
author_rank: Frequent Contributor
timestamp: April 19, 2016, 11:10:14 am
content: 512 byte forth isn't going to be able to add words. Thr general idea is that you can use a minimal one to bootstrap a larger one off disk/via serial usually so you don't have to spend all day blowing and erasing EPROMs or doing ICSP runs.Words can usually be assembly or forth threaded code. There is some discussion on how to achieve that in the links I posted.

author: rstofer
author_rank: Super Contributor
timestamp: April 19, 2016, 05:11:19 pm
content: I don't recall ever seeing a small monitor program that read entire lines. The first character of any line is the command and it is only a single char. When a particular char is received, a jump is made to the routine that handles the command or to an error handler followed by the next prompt. The command routine calls input routines that fetch the arguments. These routines (get word, get byte, etc) are common to almost all commands. The command routine would then process the arguments and do the work.It was common to just abort the command if something went wrong because it was easy. Either the arguments were fetched properly and made sense or the command was aborted.These monitor programs were designed for physical Teletypes, maybe not even glass teletypes, and handholding wasn't expected. There was never a time when the console routine would point out an invalid character in the 14th position of a line. Code size was everything!It is also important to note that the original Altair came with a great big 256 bytes of RAM. As I recall, it was possible to put a small monitor in that amount of memory. Toggling it in, byte by byte. Those were the good days of hobby computing!

author: rstofer
author_rank: Super Contributor
timestamp: April 19, 2016, 05:21:11 pm
content: On new designs, right after messing around with a monitor program, I would install a 1k EPROM containing Palo Alto Tiny Basic. I might even have the original Dr. Dobbs magazine around here someplace. As I recall, I added MEM[] as a way of reading and writing memory at a specific address. I seem to recall adding PORT() as well so I could read and write to peripheral ports. I'm not sure if the modified design fit in 1k or 2k. It's been awhile!

author: ChristofferB
author_rank: Frequent Contributor
timestamp: April 19, 2016, 07:19:17 pm
content: But then again, if it's just a monitor, single character commands are really all you need - still room for a lot of expansions.Considering how much I already mimic the Altair 8800, I think level 2 is 4K altairbasic.Palo Alto Tiny Basic looks neat too!