[force english] [force russian] [minimalistic design]
Main :> My computers: Z80,68K, etc :> 68008 SBC AVR-Booted minimal computer by DtZ with serial port MC68008
68008 computer (68kavr) by DtZ

Note the Russian Spelling of Blya-Blya-Blya!

New: Gopher Page One day it may became main page ;-)


Aim: AVR-booted 68008 SBC with CP/M 68 (yes, I've read https://sites.google.com/site/libby8dev/libby8/concept and know that idea)
Work in progress! (but mainly complete)

  The place where I bought 68008 at Feb'2014 (they are (M) chips made in 1995/6)

Board fotos:

Fotos 201412 (Start of epoch II)
Current full scheme here (updated 20150127)
(Changes with 2501.png:C3,C4 added
(Changes with 24b3.png: CTS/RTS changes, DTACK logic shown)
(changes with 24b2.png: DB5 to ground shown)
(changes with 24b1.png : 7475's trigger RST leg now shown to be at +5)

I need your's feedback. I know only one person (in USA) who dared to build that (using Arduino instead plain ATmega8).
Write to dreadbit@gmail.com

Chapter I. Idea

  Getting Reset, AVR (MCU) lowers RESET+HALT of 68008 (CPU) and begins to click clocks in main loop, which leads to the state called Boot Mode and raises CPU's RESET+HALT some clicks after that.
  Getting falling font of DS the MCU's INT0 is accured; while serving INT, main program waits until INT0 finished, so clock does not click, and there is no reason to play DTACK
UPD 20160101: It's not so in case of EC000. It hates this sort of low freqs. You cannot step-by-step debug it this way. While it loads from ATmega, it's unable to fall down where you print all that debug stuff via serial. So you have to play DTACK with EC000, and that's not as easy, but is easy, anyway
  INT0 feeds next byte of program to the CPU data bus (if CPU reads it), and leaves it there, returning from INT0 hanlder and making the main clock clicks.
   When main loop detects that DS is not active, it removes data from data bus.
So here it is:

/* Interrupt handling - DS gone low */
void ISR0()
 if (RWline is UP) {
 /* feed a byte to CPU */
  writing_on_bus = 1;
 } else {
 /* CPU is writing byte */

void main()
 bootmode = 1;
 reset_CPU(); reset_ticks = RESET_TICKS_VAL;
  /* may be some minimal delay, but CPU should be much faster then MCU*/
  if (reset_ticks > 0) 
   if (!(reset_ticks--)) 
    release_reset_CPU(); // reset - up!
  if (DS_line_got_high) 
   if (writing_on_bus) {
    writing_on_bus = 0;

While in boot mode, CPU should transfer some initial program to to memory, then MCU should leave boot mode and send reset. After reset, CPU should execute the main program already in RAM. It can later switch the clock source to run from a fast quartz.

Note 1. We have serial on ATmega, and you can use MAX232 or whatever you like to connect it to COM port or USB.
UPD: Keep in mind I utilize hardware RTS/flow control later in this project; so I'm not sure USB convertors will do the job.
20150114 UPD: Later, in 2015, I utilize CTS signal also. In 2014 version I called RTS as 'CTS' (both on the scheme and in AVR firmware), but it really, really was CTS signal, telling unix host side to pause the transmission. Scince 2015 (with versions above 2501) I call RTS signal, yes, RTS, and also I mind CTS. The CTS processing is semi-clever: if in boot time CTS is high, I assume CTS is not connected and ignore it. If it is low, I (you guessed) mind it, and pause the transmission when it is high telling CPU 'not ready'.
Note 2. It is mentioned that interrups are used to determine /DS signal. Generally, you do not need that because while CPU is clocked from MCU they are fully syncronized (and when CPU will be clocked from external source there will be no way to talk with MCU because it is slow). AVR interrupts are used because the code is clearer.

Discuss it in blogger

Chapter II. Running first command

The scheme for Running first program

The GCC source or AVR program
Warning! This file was updated at 20140416. It has a error - DEBUG was called DEDUG in .h file
Note The quartz I use for AVR is 12Mhz quartz. It can be 16Mhz [UPD: strange, I've tried and failed (!) [UPD2: because I should also add two tiny capacitors around it!]] or like that [should be configured in sources] (but not lower then 8Mhz - because the serial speed I use is 38400; if you will be happy with 2400 you can even use internal AVR clock and say that in AVR sources)
The result of running program:

(* is a clock tick , is a comment)
 Calling release reset
[Released reset]
**************************** clock after reset
INT: R         Int happens when /DS goes low; R means that CPU is READING
State 0000*****     "State 00" is some debug message, the other byte is actual byte
Releasing bus***   5 clock changes /DS from low to high; 'Releasing bus' - MCU put data bus to high impedance.
State 0000*****
Releasing bus***
State 0000*****
Releasing bus***
State 0008*****    fed with 00000008; really the address does not matter, but it must be even, -
Releasing bus***  the first thing I've got was a trap leading write 14 bytes to somewhere
State 0000*****
Releasing bus***
State 0000*****
Releasing bus***
State 0000*****
Releasing bus***
State 00C0*****  fed by stack pointer
Releasing bus***
State 0020*****
Releasing bus***
State 007C*****
Releasing bus*******
State 0000*****
Releasing bus***
State 0000*****
Releasing bus***
State 0000*****
Releasing bus***
State 0000*****       fed with movea.l #0,A0
Releasing bus***
State 0020*****
Releasing bus***
State 003C*****
Releasing bus***
State 00AA*****
Releasing bus***
State 0055*****
Releasing bus***
State 0033*****
Releasing bus***
State 00CC*****   fed with move.l #$aa5533cc,D0
Releasing bus***
State 0020*****
Releasing bus***
State 0080*****     move.l D0,(A0) 
Releasing bus***
State 004E*****
Releasing bus***
State 0071*****  fed with NOP - that's prefetching
Releasing bus*****
INT: WAA********  Writing data! Whuuuuaaaaaauhuhhhh!
INT: W55********
INT: W33********
INT: WCC******
State 004E*****
Releasing bus***
State 0071*****
Releasing bus***
State .....

So, we see that at least one command was executed by CPU
Discuss it in blogger

Chapter III. Running commands from RAM

 Well, to run program from RAM we should solder it in.
  So, the Scheme 2:

  First, note the 74138. It decodes higher adress lines. It's all clear with it. Also, that it clear that RAM should start on Addr 0h, so put the /A0000 line to /CE of RAM.

  Look at Atmega. The most significant of the new connections is the /BOOTMODE line. It is used to inform RAM to behave the following way: when /BOOTMODE is active, CPU should read not from RAM, but from MCU. It is AND-NOTed with R/W, so when /BOOTMODE is active (0) and READ(1) happens, the output of 7400 leg 8 is not active (high). When /BOOTMODE is not active and READ goes high, the output of 7400/8 goes low, and, ORed with /DS, this is fed (as /MEMRD) to /OE pin of RAM.

  7432 also ORs /DS and R//W to get /MEMWR.

   Sure, we'll use ATmega as uart, so we should connect one of the lines from 74138 (ORed with /DS) to one of ATmega's leg (again, as interrupt, while that's not absolutely needed). And add an address line (A1) to get two registers for read and for write. It's all clear that one pair is read byte from line and write byte to line, the other read register is status saying "we have an byte in input" and "it's clear to send the next char". The extra writing register is a HEX output. (UPD 201506: do not rely on it, I've found much better idea - read and write the MCU's NVRAM by CPU, but currently do not use it)

So here will be an algorythm (bold is new code):
/* Interrupt handling - DS gone low */
void ISR0()
 if (RWline is UP) {
 /* feed a byte to CPU */
  writing_on_bus = 1;
  b = bytefeeder();
  if (b != -1)
  } else { // The boot 68k program is ended!
   bootmode = 0; /* and /BOOTMODE leg*/
   reset_ticks = RESET_TICKS_VAL;
   uninstall_IRQ_0_handler(); /* or you can leave it if you plan to look at data 
    bus transfers while debugging read/write from memory; in this case it [may]
    conflict with serial IRQ */
 } else {
 /* CPU is writing byte to memory*/

void ISR2(USART_RXC_vect) // Serial event: a char came from terminal to AVR
 byte_came = byte_from_serial();
 byte_in_rx_que = 0x02; // Flag to be ORed when we'll tell CPU the status

void ISR1() // interrupt happened on /AVRSERAIL goes low
 if (RWline is UP) 
 /* CPU is reading from serial */
  writing_on_bus = 1;
  if (A2_line_is_up) // CPU reads status
   write_on_bus (clear_to_send | byte_in_rx_que);
  } else 
   write_on_bus(byte_in_rx_que); // last recieved byte from serial
   byte_in_rx_que = 0;
 } else  /*CPU is writing to bus*/
  if (A2_line_is_up)
  } else 

void main()
 bootmode = 1; /* as well as /BOOTMODE leg */
 byte_in_rx_que = 0; // No pending serial bytes 
 reset_CPU(); reset_ticks = RESET_TICKS_VAL;
 install_int1_handler(AVRSERIAL_goes_down); // Both can be done when leaving bootmode
while(1) { click_clock(); if (reset_ticks > 0) { if (!(reset_ticks--)) { release_reset_CPU(); // reset - up! } } if (DS_line_got_high) { if (writing_on_bus) { switch_data_bus_to_read_mode(); writing_on_bus = 0; } } } }

What do we feed to cpu, you may ask?
Here it is (in file bytefeeder.c):

uint8_t PROGMEM prologue[] = {
  0x00,0x00,0x10,0x00  // 0       dc.l stack pointer
  ,0x00,0x00,0x00,0x08 // 0       dc.l start
  ,0x20,0x7C ,0x00,0x00,0x00,0x00 // 8       movea.l #0,A0
, then, in loop,

uint8_t PROGMEM program_loop_bytes[] = {
 0x30, 0xFC, 0, 0, // move.w #XX,(A0)+
 0x4e, 0x71 // NOP
, replacing zeroes by the bytes from the actual program. The trailing NOP is needed because 68008 prefetches one command before executing the prevous (as shown in Chapter II)
Note: In early versions of code there was a real NOP for every byte; later, I was clever enough for only one NOP for whole program

And here are the tits is current photo of my board (20140118)

K1533LA3 = 74ALS00, K1533LL1 = 74ALS32, K555ID7 == 74LS138 (Soviet/russian chips)
The GCC source of AVR program for chapter III

discuss it in blogger

Chapter IV. Switching to fast clock

  We will add fast clock. Just will, because out current CPU clock is slow. And for future 68681 UART which I am planning.

  On my opinion, our AVR clock is about 60 times slower then external clock. (I run ATmega8A from 12Mhz crystal).

  So lets' add an external quarts. (around 12 in my case; it will be devided by 2, read more). We will use
the Searle Grant's scheme on 74HCT04 and get FASTCLK signal pins 3,4,5,6. And a trigger - 7474 (should be ALS or HCT, but I've tried old 7474 and it worked too.) The trigger (1-7 pin) will behave the following manner: on reset, it will be at 1 (CLKFROMAVR high), and by accessing E0000 address it will go low, that will be switching to fast clock. Also, by accessing C0000 from CPU you can switch it back to AVR clock. So we will mix /C0000 and /CPURESET signals on 7400, so it will go high when any of /CPURESET and /C0000 will be active, and invert it on 74HCT00 pins 0 and 1. Then, we'll take the trigger output (CLOCKFROMAVR and /CLOCKFROMAVR) and mix it with CPUCLK on one segment of 7400 and with FASTCLK. We'll get AVRCE (AVR Clock Enabled) and FCE (Fast Clock Enabled) signals. When any of them disabled, it will go high, the other should tick. And let's mix them on one extra 7400 to get MIXEDCLK2

 Is MIXEDCLK2 is good for clocking CPU? Maybe, I'm not sure.

Imagine you switch from AVR clock by accessing E0000, and fast clock front comes right after that? That may be not good (because that will lead to a very fast clock tick) (or may not, because when you switch the trigger you are at the end of cycle)

  So let's use the other side of the moon 7474 trigger it to revert on any even clock change. (And this devides clock by two.) I do not remember why I've decided that, but I really thought we'll have one guaranteed tick in the worst case; it looks I'm wrong.
Anyway, this works ;-) (it really was an argument of doing it, but I forgot)

  And unsolder CPUCLK clock from CPU and connect it to the output of that trigger (called CPUCLK')

20140213 Well, here it the worst case this trigger prevents: imagine we switch the clock from slow to fast, and the MIXEDCLK2 is high. And saying when switched to fast clock clock is low and just before rising edge. So, the MIXEDCLK2 will go from high (from AVR) to low and back to high too fast.
This is the case this trigger prevents.

Click to ENLARGE YOUR'S PEmy scheme

  We've never discussed M68K assembler code; some code in examples, but now it's time to speak about it. Currently I use A68K assembler [local] (not pila) to get binary output of program; it has $1D bytes prefix (is it for HP calc?), so I cut it and translate the rest of binary to C code via bin2c.tcl script. While what you see in the 68K code is very experimetal (this is my first attempt to write 68K code), at least here you can see an example (in byteio_fast.asm) file how to read and write bytes via AVR UART emulation

uartstat equ $A0002
uartdata equ $A0000
slowclock equ   $C0000
fastclock equ   $E0000

;------------------ RX char
    bsr rx_notempt      ; while rx is not empty, ie, no char
    beq rx_char         ; loop
    move.b      d0,(slowclock) ; switching clock slow
    move.b      (uartdata),d0   ; read from uart
    move.b      d0,(fastclock) ; switching clock fast
    cmpi.b      #CTRLC,d0       ; CTRL-C? 
    beq warm    ; warm reset

;------------------ Test input for a char (NOT ZERO if IS)
    move.b      d0,(slowclock) ; switching clock slow
    move.b      (uartstat),d0
    move.b      d0,(fastclock) ; switching clock fast
    andi.b      #$02,d0 ; bit 1 is 1? (I've told you that it is my first attempt to write 68k code!)

;------------------ Wait for clear to send -------
    move.l      d0,-(sp)
    bsr tx_rdy
    bne tx_rdy_w1
    move.l      (sp)+,d0

;------------------ TX char
    bsr tx_rdy_w
    move.b      d0,(slowclock) ; switching clock slow
    move.b      d0,(uartdata)
    move.b      d0,(fastclock) ; switching clock fast
;----------------- Returns TX ready (Z)
    move.b      d0,(slowclock) ; switching clock slow
    move.b      (uartstat),d0
    move.b      d0,(fastclock) ; switching clock fast
    andi.b      #$01,d0

The most interesting in this code is that it is working. I do not know what to tell you about this code, may be the only thing: do not forget to switch the clock fast in your's main program

The GCC source of AVR program for chapter IV
Discuss in blogger

Chapter V. SD interface

  The idea of SD interface is just an adoptation of my SD interface for Searle's Grant SBC. So go there for SD card pinout, resistor values, 3.3V power, etc. The only change is 2*7474 to one 74175. Or you can use 2*7474. Or any latch of this sort.
  Some notes: a rewiring /AC0000,CPURESET->SETAVRCLK, FCE,AVRCE->MIXEDCLK2 on the scheme is not significant at all and is here just to correspond my actual wiring.
  As for SD interface, it consists of a 74175 trigger for data output and 7403 as data input. To write to 74175 we mix /A80000 line with /MEMWR and /DS (on an extra 7432) and latch D0-D2 to the trigger, so that are SD card's Clock (SDCLK), DataIn (SDDATAIN) and Chip Select (SCCS) [why SCCS? Rename it to SDSC later] SPI lines. They should be mixed via resistors to get 3.3V-alike signals (again, see this). Do not forget that SD card itself should be feed with +2.8 - +3.3V so you can use 7833 or just a LED to drop the voltage.
  For data in, we mix /A80000 line with /MEMRD and /DS to get /80000RD and invert it to get 80000RD. Passed throw 7403 (with SDDATAOUT) we direct this open-collecor output to D0. So this output is low only when 80000RD is active (high) and SDDATAOUT is high too, so this is inverted input.
So, from 68k side we can

    move.b	#7,$80000 ; CS - up, Dataout - up, CLK - up
    move.b	#2,$80000 ; CS - down, Dataout - up, CLK - down

manage that bits this way (but better keep higher bits high - we may have some extra SPI devices in future), and
to read it just read lower bit from $80000 and invert it.

Just to remind:
D0 - CLK
D2 - CS
D3 and D4-D7 - reserved for future SPI devices (who knows which? extra Atmega, RTC, etc)

  The Code for ChV can detect (command "BOOT") the card (CMD0), can send it CMD1 for (doing smth usefull), some command to ensure the card's sector size is 512 bytes, but nothing more still.
(I use this and this) as reference)
   Also, scince now I use Atmega's PC5 pin for CTS. That's because I've tried to cut-and-paste CP/M-68 S-record files and was unable to do that without hardware flow. So in AVR code there is a #define WITH_CTS to use this code (enabled by default) and 256 bytes ring boofer for handling input bytes from serial.

   As you could note, there is a sort-of-monitor program included in 68k asm
Currently it can:

BF Blink SDCLK fast (with fullspeed clock)
BS Blink SDCLK slow (with AVRCLK)
BLINK Blink until key pressed (fullspeed clock)
ON Set SDCLK to 0 (or 1)
OFF Set SDCLK to 0 (or 1)
1 Set SDCLK to 1, SDDATAIN to 0, SCCS to 0)
2 Set SDCLK to 0, SDDATAIN to 1, SCCS to 0)
4 Set SDCLK to 0, SDDATAIN to 0, SCCS to 1)
IN Tell SDDATAOUT status (or inverted SDDATAOUT?)
DUMP[optional address] Dump memory from address (or continue to dump from that address if no address given)
BOOT Try to init the SD card
S[srecord] Parce S-Records. It understands S1,S2,S3 records and ignores all the others

It's easy to extend this command set:
first, write an f_myfunc subrotine which should return to monitor with rts.
Then add it's mnemonic to commands: and it's address (f_myfunc) to commands_vector When called, A1 will point to the first byte after you's command mnemonic in input buffer, so if was called as


, A1 will point to "bebebe"
   Also there is one more thing I want to warn you: I use ISP programming of ATmega via SCLK/MOSI/MISO/RESET pins of ATmega, AND THIS IS UNRELATED TO SPI BUS WE'VE JUST DISCUSSED!
  Be careful: I've burned 3 Atmega's while ISP programming it until I installed a RESET switch for CPU (RESET+HALT)
So to make an ISP firmware update, hold down RESET+HALT of CPU, then do firmware update (I use avrdude and usbasp)

Chapter VI. CP/M - Part I

20140325 Some news of the project:
The updated scheme Here. Generally nothing new, only MAX232A is drawn

Here is the picture of my board taken 20140325

  First, I have some minor (but nice!) changes in my firmware. First is

GOaddressmonitor command , which goes to the specified address.

And the second... (have I ever told you I'm genius? REALLY? Oh, sorry) - I catch the BREAK from a serial line and inititate CPU Reset! (actually, even MCU reset).
So, in C-Kermit> (if you use C-Kermit as do I) 's terminal mode, I can press [CTRL]+[\] [B] , and get a reset!
More, I own an HP 9000 A500 server and it has as "Service Processor". And I'd like to have a full Service Processor console in future like the one on that server. Saying, it can turn on and off ATX power (if I have a spare pin and free memory on Atmega8).... Sometimes in future

So, let's talk about CP/M iteself

   This is my first attempt to port CP/M to any computer by the method explained in, our case, "System Guide". The prerequestings are:
  • I should have System Guide (I do)
  • I should have CP/M 68 in S-records (I do from http://www.cpm.z80.de/binary.html : I use this)
  • The system must accept S-Records (my does)
  • I must have an assembler which generates S-Records (I use A68k from TI 68K calculator project: [local]
    68000 Assembler - version 2.71.F3s (Sep 21, 2004)
    Copyright 1985 by Brian R. Anderson
    AmigaDOS conversion copyright 1991 by Charlie Gibbs.
    Adapted for use with Fargo by David Ellsworth.
    Bugfixes and additions by Julien Muchembled, Paul Froissart and Kevin Kofler

    Warning: do not use asm68k
    asmx multi-assembler version 2.0b5
    Copyright 1998-2007 Bruce Tomlin
    - buggy as shit. May be vasm is good - but I'm not ready to write linker scripts just to get SRecord from
    the source with static lables and given ORG)
So, on the CP/M distribution there is a file CPM15000.SR - that's an CP/M in S-Records (which is loaded from address $15000).
On the first disk of distribution set there is a very useful README.TXT which says that to create a BIOS I should figure out _init (== ORG of BIOS == $1B000) and _ccp ($150BC) symbols in CPM15000.MAP (and that differs from what is written in "System Guide"; there said you should patch Srecords file [for 1.0 and 1.1 CP/M 68k vers.]).
   So lets go to "System Guide" directly to the Appendix B on page 59 and start type "Sample Bios" into text editor.
   As you can see, BIOS install TRAP #3 and CP/M works with BIOS via this TRAP.
I've tried to start with
  • constat
  • conin
  • conout
, but it was not enough; setexc also a must for CP/M to show you it's A:>. The first thing it does, it installs an TRAP handlers for almost all the TRAPS!
I will not retype it here, that will be attached later, when it will be at least read/write sectors.
To start CP/M first load CP/M itself, then BIOS, then type go15000
After I wrote basic sector read/write access I was able to say DIR,TYPE and even REN. But could not run any program, that's because I've forgot getseg call at all. And then I was able to run DDT68000, but during read it compained "Cannot write sector" (and it was not writing sector at all!). That was because I forgot flush call.

Funny - this code contains *No* CP/M specific code yet, and is just update of firmware ;-)
Code for ChVI
Discuss in blogger

Chapter VII. CP/M 68, booting from Srecords

  Ok, lets start from code. Code for ChVII
  The firmware is mostly [or exactly?] the same, but there are two new directories - BIOS ,which contains BIOS (sort of ugly bios), and Disk, which contains pretty empty disk image and diskdefs for cpmtools. (local) The disk image itself contains A: - P: drives, cpmtools with this diskdefs are able to write to A: . Write there a whole CP/M distribution.
The disk image comes from Searle Grant's Z80 SBC, (or even my mentioned SD interface for it) as all the DPB stuff.
  For the bios reassembly use assemble script, you'll get bios.s. Next, load it and CPM15000.SR via cut-and-paste to SBC console.
  Personally I do it with kermit. It's much better for our use then saying minicom.
  Here is my kermit initialization (I hope I forgot nothing:)
set line /dev/ttyS0
set car off
set speed 38400
set flow rts
set transmit timeout 10

(and set input echo on, but I forgot what it is for and if it is really needed)    So from SBC prompt say
* boot
, it will initialise the card and load something ($2000 bytes?) to somewhere ($1000?). But currently we do not care.
   UPD: Yes, it loads 16K to $1000. But after 0.00.01 release (or what's forthcoming for 201409? that will be changed: it will load to $8000 with stack at $2000; before that release, stack in $FFE)
  Next, load bios.s and CPM15000.SR by

 C-Kermit> transmit CPM15000.SR


 C-Kermit> transmit bios.s

Next, run it via go15000 and get A:.
  The next thing is to create CPMLDR and CPM.SYS. Sure, we will create them on the board. But I refuse to learn CP/M ed!
So, the next thing I going to do is to get some text editor. And that will be separate chapter or two.

(UPD 20140520 In this wonderful David Schultz's CP/M 68K simulator a *working* vt100 emacs included; the simulator is very useful itself, too; so currently I gave up porting both Terry McConnell's deadlin and FreeDos's edlin)

Some things to mention:
  • First, get .68K files from .REL . That's done by series of RELOCX.SUB scripts
  • if AS68 says can't open 0:AS68SYMB.DAT, ensure you have AS68INIT from DISK3 and run AS68 -I AS68INIT for every TPA change (or system relocation; look at Programmers Guide)
  • http://forums.debian.net/viewtopic.php?f=16&t=112244" A very good article how to recalculate DPBs into cpmtools diskdefs.
    It does not help me much because it is long and clever; I always guess some things (and probably wrong)
  • On Solaris/Sparc I access the disk with cpmtools like that:
    /usr/local/bin/cpmls -f sga /vol/dev/dsk/c2t0d0/unknown_format

Chapter VIII. CP/M 68, building CPM.SYS and CPMLDR.SYS

So, currently we have a board which can be loaded with CP/M, we have C compiler there, and out aim is to build CPM.SYS and CPMLDR.SYS.
In this point I had to transfer some files without pluggin SD card off the system; that's why I got some UUDECODE program
(C source and .68K on disk B:), and able to transmit uuencoded files there. That's not too fast, but quite good for transfering sources.
So I have to assemble the source of my bios.asm file on the board. Here what to be done:
  • Add some more assembly conditions - AS_SRECORD, AS_CPMLDR_BIOS
  • Replace my long labels like write_sector_loop_2_exit_ok: to the 8 chars lables like WRSL2E1:
  • Convert file to CP/M style text(add ^Ms and ^Z)
  • replace comments starting with ; to *
So, I use Linux/GCC's cpp to replace labels.
To do it, I wrote defs.h which should be #included in the beginning of bios.asm. Also,
edit include "dph.asm" to became #include "dph.h" and run it via cpp and then transfer it into SBC's disk
   Hopefuly, I've done it all and included the whole disk image. To boot it, first say
* boot
it will load first 16k of disk to $1000 , then
* go1080
First $80 bytes are useless in our case, the linker just appends something there, but we do not care.
To regenerate system follow the System Guide (the system is $18000 based; do not forget to mention memrgn) ; also, there is readme for whole the disk and readme on disk b:; there is mkldr.sub which should run from disk c: - that's linker batch to generate cpmldr.sys.
  After you get it, XPUTBOOT b:CPMLDR.SYS A: - and you'll get the bootable media. I use distrubuted xputboot because I'm lazy to rewrite it;
so I linked and wrote the cpmldr.sys and watched what I've got - and $1080 was the starting address. Why not?
20141027 Also there on disk B: you can find the source for SDHC versions of BIOS and Loader BIOS; as the main (SD) BIOS and LDRBIOS they are made from bios.asm unix file, the only difference are the defines. The problem is that I cannot edit them on board with emacs - it has not enough memory.
CPMTOOLS Diskdefs for the disk is
diskdef sga
    seclen      512
    tracks      512
    sectrk      32
    blocksize   4096
    maxdir      512
    boottrk     1
    os  2.2

On Solaris/Sparc I access the disk with cpmtools like that:
/usr/local/bin/cpmls -f sga /vol/dev/dsk/c2t0d0/unknown_format , on Linux just like /dev/sdb

Code for ChVIII, with disk image included

(Is that's all? I cannot believe that!)

Chapter IX. Future plans

Those plans are visible in some future
  • CP/M : disk deblocking (because disk write is TERRIBLY SLOW!)
  • CP/M : make a bios call and simple command (like diskmap i: 21[map disk i: to be 21th disk])
    to map disks. We still use only 128M of our 2G cards.
  • TOS/M, EmutOS (I've never seen it)
  • Hardware : Atmega based advanced (cause we allready have basic - we can reset it!) LOM; so, maybe move
    to Atmega328 or Atmega168
  • Hardware : use of Atmega's NVRAM, sort of environment maybe
  • Hardware : IDE drive (not CF - we hate each other)
  • Hardware : MC68681 (or smth else), interrupt driven, sure
Those are secret invisible plans
  • MC68008 powered manned Europa flight

Chapter X. Some user experience.

Any my future experience will be added in this chapter

20140707 Oh yes, gkermit for CP/M 68 [local] works nicely, the only thing to mind - do not forget to set sending block size to saying 64 bytes and convince unix side kermit not to turn on streaming. (or maybe it's my problem; looks like my unix side ignores RTS(!); the maximum I get out of it is 114 CPS)
When I tried to recompile it, I found that stty.h is missing in CP/M 68K 1.3; author (George Harvey) of GKermit port for CP/M-68 says it is really missing and should be looked at 1.2 release (or even 1.1)
Also, keep in mind that it thinks of CP/M 68 side as "unix kermit", so it does not automatically translates text files
20141113 Adding memory up to 512k is easy. I added extra 128K today - so I have 256K today.

Chapter XI. Multiboard configuration.

20141209   During summer of 2014 I was carving backplane like a timble beetle, and I did it! (see the fotos on top of this document). So the first thing I've implemented is change the CPU to CPU board with MC68EC000 (also I could use MC68HC001) - both of these chips has 8-bit data bus mode (and SEC000 is currenly in production by FreeScale). The thing EC lacks is 6800 signals; but I do not care, because I never plan to use MC6850 chip (is there a reason to use some other 6800 family chip? [except MC6809, but not in this project], and MC68008 lacks some signal of 6800 interface, too (well, it can, but it takes some more glue logic).
  Generally it just plugs: I currently use only A0-A19 address lines (but I have an idea to change it), I ground MODE leg (==set data bus to 8 bit), and used /LDS as /DS signal (because of 8 bit bus, according docs)
  Know what? It ran from the first try!
  My MC68008 is 10Mhz (but I ran it from 16Mhz/2 = 8Mhz [but it known to run at 10Mhz]), my MC68EC000 is 12 Mhz, but in the time of writing it runs on 20Mhz/2 = 10Mhz. I hope I'll get 24Mhz quartz in a few days and 68EC000@20Mhz in a two weeks. Also I expect some fast memory to arrive.
The part that I had to change is 74ALS74 (which generates MixedCLK2 signal) to 74ACT74 (I do not know what exactly it is, but I was told that it's "All better then soviet K1533TM2 (==ALS74)") - it lost some clocks in multiboard configuration.
  I still not absolutely sure it's all right with the boards [mostly with contacts], but most of time they works all together, so generally the idea is working.
  Also I added one more quartz (fail-safe 16Mhz and full-speed [currently 20Mhz]), selectable via jumpers.
  So, what I've told about future plans? Looks like they may come true!

Release updates

   Naming for releases
\   / \/
  ------ > project name, 68kavr
      YY   Year, 1990 based (DtZ's tradition; 24 for 2014)
        M  Month - '1' for jan, '9' for Sep, 'b' for Nov 
         R Release this month

Flag Counter Flag counter for 68kavr Epoch I only
20141128 Gopher server launched
20141022 2006 Fotos from the roof of my house
20140701 New artwork: "I am stoling Robotron 1715 PC from MESI" for my robotron pages
20140616 Update: 68008 computer by me
20020601 Redisign of my homepage. Still wondering, what's for?
© DtZ 2002 - 2006, 2037