Author Topic: Getting an MVME320B (Motorola VME HD controller) working  (Read 1894 times)

0 Members and 3 Guests are viewing this topic.

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Getting an MVME320B (Motorola VME HD controller) working
« on: May 02, 2024, 04:39:20 pm »
Hi

I'm reaching out to see if anyone has experience of the Motorola MVME320B disk controller card.

This is quite a long posting, but the bones of it are:  I have hooked everything up and to all intents and purposes, the disk controller does not show any sign of life on the HD interface ports no matter what I do.  I can see evidence that the disk controller is not dead on the VME bus side.

The detail is as follows;

My hardware set up is a VME rack containing two cards;
  • MVME110 processor card with a 68000 running 110Bug V4.1.  It's fitted with 32K bytes static RAM
  • MVME320B disk controller card with V4.2 firmware.  This is the later version of the card which does all the disk I/O through ribbon cables out the front of the rack.

The processor is in the left most slot and the disk controller is directly to the right of that.

I am only trying to connect a hard disk, I've not attempted anything with floppy disks.

I don't have any instructions for 110Bug but reviewing the source, I can see that there are basically two families of disk related commands;
  • VersaDos boot through the "B*" commands.  These have options on what to do after the boot blocks are loaded
  • Low level interaction with the disk controller through the "IO*" commands

I don't have a valid VersaDos image so my investigations only relate to the low level commands.

Actually I don't even have a real hard disk.  I'm using one of these;

https://www.pdp8online.com/mfm/mfm.shtml

this has the advantage that you get some diagnostics while it's running and I can create just about any topology of disk that I want.

The processor card serial port is connected to a Terminal Server like this;

https://amzn.eu/d/3c6rNQY

which comes in handy as I'll explain in a minute.   Basically I can run puTTY across my LAN and at the same time send sequences of keystrokes to the processor using a little program I wrote.

A characteristic of VME cards of this era is JUMPERS!  They're everywhere.  Also there seems to be a sensitivity to hardware/firmware revision status plus of course, the card(s) might be faulty.  Anyway back to jumpers, I used the information here to set the jumpers;

https://bitsavers.computerhistory.org/pdf/motorola/versados/MVMEVDOS_D2_VMEHwSwConf_May85.pdf

This works well for the processor card but unfortunately the disk controller card information relates to an earlier version of the card and the jumper layout has totally changed.

So what I did was write down all the settings for the earlier version of the disk controller in the guide.  Then I used the old disk controller user manual here;

http://www.bitsavers.org/pdf/motorola/VME/MVME320/MVME320_D1_Disk_Controller_Users_Manual_Feb85.pdf

to figure out what each jumper does and what it's set to.

Then I went to the user manual for the new version of the card which is here;

http://www.bitsavers.org/pdf/motorola/VME/MVME320/MVME320B_D1_Disk_Controller_Users_Manual_Jan88.pdf

and using the information from the old card, I made sure that my settings are correct.  I was heartened to see that actually there are no changes required from "default" which is good (I think).

There are two problems with this process

  • There are many more jumpers on the new card so I just them to "default".  I don't think this is a problem because most of the new jumpers relate to Floppy Disk options which I'm not too bothered about.
  • In the User Manual for the older card, there is a section on "MVME320 backplane settings".  This does not exist in the new card manual.  Am I missing something to do with the backplane?  Do I need to set something here too?  I've assumed that the old manual is referring to the breakout panel, an MVME702 I think it's called.  Anyway this mystery table is attached as a photo if you take a look.

So I turn everything on and set my HD emulator running.  It starts without error.  I think it works because I've used it on PC's without a problem.  I have a crude Logic Analyser connected to the HD control signals and although it's crude, I know that if anything moved, I'd at least see a trigger trace on the LA screen.  As I implied back at the top of this posting, it's always showing "Everything high"; in other words, fairly dead.

Because I don't have any documentation for 110Bug, I don't really understand what each command does.  There is Bug documentation on cards like the MVME177 but the functions of each IO* command is massivly expanded and so is of limited use.  I'm not good enough to figure out what the commands do by reading the source (sorry).  I find it amazing that the code could contain so much annotation without actually explaining what user function is provides anyway the authors will have assumed the reader had the User Manual....

I have figured out that in general, all the disk related command seem to take two arguments representing the HD ID and the controller.  My HD is a number 0 and my controller is a number 4.  I got this from the card user manuals.

So first of all we have IOT and IOP.  I think IOT teaches the controller about the geometry of the connected drives and IOP enables direct physical interaction with the drive.  So getting to actually try something, if I enter;

Code: [Select]
IOT
or

Code: [Select]
IOT 0,4
or

Code: [Select]
IOP
or

Code: [Select]
IOP 0,4
The bug hangs and after about 20 seconds, the Fault LED lights up on the processor card.  The only way out is a reset.

This leaves us with IOC which enables the user to set up a control block in RAM and then (I'm assuming) point the disk controller at it and let it carry out the command.

I don't know, but I'm assuming that the difference between IOC and IOP is that the former uses a RAM based control block (called an ECA in the manual) where as the IOP command enables you to poke the disk controller registers directly. That's just a guess of course.

So if I enter;

Code: [Select]
IOC
Then there is a delay of about 60 seconds and I get a prompt to enter the drive number, then the controller number.  I enter 0 and 4.

I am then presented with a PARTIAL memory dump of the ECA and I'm asked if I'm sure.  I say "Y" and the bug goes dead for about 30 seconds and finally returns a PACK error.

It's interesting that the ECA is longer than the memory dump.  Don't know why this should be but it's missing the geometry section at the end.  Not really a problem but interesting.

When I do a dump of the ECA following the command running, I can see that the main status is $07 which is "Card busy".  I don't think any other part of the ECA is altered.

This is really good because I'd like to think that the disk controller tried to do something and timed out.

Turning to the memory locations used by the disk controller card, if I dump the odd addresses, I see values.  If I dump even addresses, I get bus errors.  If I remove the card and try again, all memory addresses I try to dump give bus errors.  This gives me hope that the disk controller is not totally dead.

Returning to the ECA, loading it by hand is error prone so I wrote a little loader program that sends keystrokes to the serial port.  This is a dumb process, but it does seem to work.  Here's a list of the ECA I set up;

Code: [Select]
# Start loading the ECA as per MVME320 User Manual pg C-9
# Commands described pg 6-1
# Zap the buffer back to 00
bf 110 170 00
# Zap my sector buffer (not that I need one for the command I'm using)
bf 1000 1800 00
# Fill the ECA
m 110
# Command code (Recalibrate to track 0) $00
00
# Main status $01
00
# Extended status (Should be 00 before command) $02
00
00
# Max retries $04
0a
# Actual retries $05
00
# DMA type $06
00
# Command options $07
00
# Buffer address (Hi word) $08
00
00
# Buffer address (Lo word)
10
00
# Buffer length requested $0C
00
01
# Buffer length transferred $0E
00
00
# Cylinder number $10
00
00
# Head number
00
# Sector number
01
# Current cylinder position $14
00
02
# Reserved $16
00
00
00
00
00
00
00
00
00
00
# Pre index gap $20
00
# Post index gap
00
# Sync byte count
00
# Post ID gap
00
# Post data gap
36
# Address mark count
03
# Sector length code
01
# Fill byte
e5
# Reserved $28
00
00
00
00
00
00
# Drive type - Soft sectored, Hard disk with CRC $2E
03
# Number of surfaces $2F
04
# Sectors per track $30
0a
# Stepping rate $31
06
# Head settling time $32
46
# Head load time $33
46
# Seek type $34
02
# Reserved (Phase count) $35
00
# Low write current $36
00
50
# Precomp cylinder $38
00
50
# ECC remainder $3A
00
00
00
00
00
00
# Appended EEC remainder $40
00
00
00
00
00
00
# Reserved $46
00
00
00
00
# MVME320 working area $4A
00
00
00
00
00
00
00
00
00
00
00
00
# Reserved for the controller $56
0f
f0
# Get out of data entry mode
.
# Present a dump of the commannd
md 110 5f
# Actually send the command to the MVME320
# ioc 0,4

and here's the program that loads it (via that Terminal Server I mentioned before).

Code: [Select]
# Send a series of keystrokes to an MVME110 serial port via a terminal server connected
# on the LAN.  The keystrokes are held in a file, e.g. keystrokes.key

# D. Waine 27/04/24

# In order that this program function, you need to have the TS and the MVME110 switched on (!)
# then start a terminal session using puTTY to the TS.  Run this program and the
# key strokes will load.

import sys
import os
import socket
from time import sleep

# Location of the TS on the LAN
terminalAddress = '192.168.0.3'
terminalPort = 8234

if len (sys.argv) != 2:
    print ('Incorrect number of arguments.  You need to supply the input .key file without an extension')
    sys.exit (2)

filename = sys.argv [1]
fileExtension = '.key'
inputFile = filename + fileExtension

lineCounter = 0
outputCounter = 0

# Open the input file
print ('Opening input file: ', inputFile)
with open(inputFile) as inFile:
    print ('Opening output stream to MVME110')
    sock = socket.socket()
    sock.connect((terminalAddress, terminalPort))

    print ('Connected')
    sleep (0.1)
    # Read it a record at a time
    for line in inFile:
        # Trim the input line of CR/LF & any spaces
        inputLine = line.strip()
        # Bump the correct input record type counter
        lineCounter += 1
        if inputLine [0] != '#':
            sock.send ((inputLine + '\r').encode())
            sleep (0.1)
            outputCounter += 1
    sock.close()
print ('Input records: ', lineCounter)
print ('Sent records:  ', outputCounter)

If anyone can shine a light on any of this, I'd be grateful.

Thanks for your attention.

Dave


« Last Edit: May 02, 2024, 04:48:23 pm by LittleFrog »
Dave
 

Online marcopolo

  • Regular Contributor
  • *
  • Posts: 164
  • Country: fr
  • F4LIG
    • Retronik
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #1 on: May 07, 2024, 08:04:13 pm »
IOT is normally an interactive command used to define disk parameters.
Take a look at the MVME101 documentation, which describes how to use the MVME319.
My Archives (68K, Old logic, SSB radio): marc.retronik.fr
 
The following users thanked this post: LittleFrog

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #2 on: May 08, 2024, 07:12:09 am »
Good morning MP, thanks for the really useful tip. 
Dave
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #3 on: May 13, 2024, 07:00:40 pm »
Hi

Just wanted to provide an update....  The MVME320 uses DMA to transfer data to/from connected disks.  The only RAM I have in my system right now is on the MVME110 processor board.  Reading a general document about the Motorola product line which you can find here;
http://www.bitsavers.org/components/motorola/_dataBooks/1984_Motorola_16_32_Bit_Microcomputer_System_Components.pdf
In the chapter about the MVME110 (pg. 1-20, "Local memory", para 2) it says that;
Local on-board RAM is not accessible from the VMEbus

Further, reviewing the source of the 110Bug, in program BO320.SA  (the MVME320 driver routines), here's a fragment of code starting at line 416 with comments;
Code: [Select]
         MOVE.L    ENDON,D1            END OF ONBOARD RAM ADDRESS
         SUB.L     D2,D1               CANNOT USE ONBOARD RAM WITH VME320
         BLT.S     SETBUFR             OK?
         MOVE.L    #'RAM ',D1          No... Setup Reason for error message
         BRA       ERRORG              .     and exit
I take the code and comments to indicate that if you're trying to transfer data to/from a RAM address that's on the MVME110, exit with a "RAM" error.

Putting all that together, I think I need VME bus RAM to get anywhere.

Dave
Dave
 

Online marcopolo

  • Regular Contributor
  • *
  • Posts: 164
  • Country: fr
  • F4LIG
    • Retronik
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #4 on: May 13, 2024, 07:18:22 pm »
Try to to find an MVME202 or 222 DRAM board.
My Archives (68K, Old logic, SSB radio): marc.retronik.fr
 
The following users thanked this post: LittleFrog

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #5 on: May 13, 2024, 08:49:11 pm »
Hi Marco

Thanks for the tip.  I have managed to find several people who might have an MVME221 (static RAM) but I have no User Manual and as there are a mass of jumpers (too many for me to work out), I will look for a D-RAM alternative as you mention (manual on BitSavers).
Dave
 

Online marcopolo

  • Regular Contributor
  • *
  • Posts: 164
  • Country: fr
  • F4LIG
    • Retronik
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #6 on: May 14, 2024, 07:42:04 am »
I have managed to find several people who might have an MVME221 (static RAM)

Hi Dave,

Are you sure it's an MVME221 and not an MVME211?
« Last Edit: May 14, 2024, 12:13:04 pm by marcopolo »
My Archives (68K, Old logic, SSB radio): marc.retronik.fr
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #7 on: May 14, 2024, 03:43:36 pm »
Sorry.  It's an MVME211 as you say.

I've worked out some of the jumper settings but others (like base address and chip size) are beyond me.

Kind regards,
Dave
 

Online marcopolo

  • Regular Contributor
  • *
  • Posts: 164
  • Country: fr
  • F4LIG
    • Retronik
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #8 on: May 14, 2024, 03:51:09 pm »
Hello,

I have this documentation on MVME211 jumpers

Regards,
Marc
My Archives (68K, Old logic, SSB radio): marc.retronik.fr
 
The following users thanked this post: LittleFrog

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #9 on: May 15, 2024, 07:57:57 am »
Morning Marco.  Amazing.  I'm so grateful.  Thanks.
Dave
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #10 on: May 20, 2024, 03:05:10 pm »
Having obtained jumper information (thanks Marco), I have been able to reconfigure the MVME211 so it BASICALLY works with my set up.  I thought this might be useful for others if I documented my experience here...

First off, I don't have a lot of experience with 68K, so there may well be some school boy errors in here.  It's very likely that I've misunderstood something and so treat this information with suspicion and assume that there's at least one serious error (but I don't know where :)).

Furthermore, there is a serious problem with testing the board after config.  I explain at the bottom of this post.

I'm using revision P of the MVME211.  This maybe important because some of my comments refer to component positioning which might have changed.

I'm trying to fit 16 off 32K * 8 RAM devices (HM62256ALP-10).  This is going to be configured as two address contiguous banks of 8 off devices, each bank having 256K bytes.

We're going to being using a base address for the whole board of $040000.  The first bank will have a base address of $040000 and the second bank will have an address base of $080000

Referring to the PDF attached to one of the previous posts, pg 2.

Looking at the jumper pin signal information in the centre of the page, I think it's correct.  These jumpers control what signals are fed through to memory device pins whose function varies depending on the device being used.  It would be useful to know the function of each jumper group.  This is what I found with a continuity tester;
  • J1/J3 control what signal is fed to pin 26
  • J6/J7 control what signal is fed to pin 1
  • J12/J13 control what signal is fed to pin 27
  • J2/J4 control what signal is fed to pin 28
  • J14/J15 control what signal is fed to pin 23
Given that I am trying to use HM62256ALP-10 devices, there is a massive problem with the above....  If you look at the memory device data sheet, A14 is on pin 1.  In the case of a 68000, we need to connect A15 to this pin.  As you can see from pg.2 of the PDF, J6/J7 only allow;
  • A16
  • +5VDC
  • R/W
to be connected.  For this reason, I traced out where to find A15 so I could "hot wire" the correct signal into pin 1.  Results as follows;
  • A15 is on buss connector P1, row C, pin 23
  • This goes to an 'LS373, U22, pin 13
  • This signal pops out on U22, pin 12
  • This then can be found on jumper pack J8/J16, pin 8
So the upshot is, don't fit any links to J6/J7 but hot wire J8 pin 8 to any pin on the top row of J6 and J7 (the top row pins are linked on the PCB).

In general, Motorola  documentation shows the jumpers in the correct orientation (e.g. Rotationally correct when viewing the PCB with connector P1 top-right).  There is a major gotcha with J2/J4.

The information is wrong, I think there are two faults and unfortunately there is no easy way of describing this because you can't just rotate or mirror the diagram.

The jumpers are fitted left-right on the PCB, not north-south.  Getting this wrong will short the battery and main +5VDC supplies.
In summary, if you look at the PCB;
  • The pins nearer the top of the PCB are +5VB
  • The pins nearer the bottom of the PCB are for +5VDC
Back on pg.2 of the document, With the above in mind, and assuming you're going to use +5VDC to supply the memory, "most" the example settings at the top of the page are correct but J2/J4 should be rotated 90 degrees anti clockwise and you should also re-number the pins (look at the PCB to see what I mean).

I said "most" because the example of 16K * 8 MCM63128 is actually correctly orientated (but the pins are still incorrectly numbered).

I'm assuming that jumper information for the 2 types of 8K * 8 RAM devices was unintentionally left blank.  It doesn't make sense as-is.

Finally on pg.2, I used the "logical equivalent number 4" setting which is for 32K * 8 devices.

Moving on to pg.3 of the document...

The RAM devices I'm using have an access time of 100nS (-10 part code) and so I selected "110nS" on J21/J23.  This might not be the right thing to do, but it seems to work.

OK.  Now the hard part.  I found the base address setting really difficult to understand.  Here are some comments/thoughts;

All the address selection jumpers are shown rotated through 180 degrees.  For example, J9/J17 GND signal is on the RIGHT of the jumper pack when the PCB is viewed in the normal orientation not the left.

The pairs of jumper packs are shown left/right reversed.  In other words, the diagrams show J9/J17 to the left of J8/J16.  This is incorrect when viewing the PCB in the normal way.  Actually J8/J16 are on the left, J9/J17 are on the right.

I can see why the documentation does this, but it's something to bare in mind. (Showing the jumpers this way round makes it easier to read the address bit pattern).

Taking the above into account, it's a shame that the "memory device capacity" table shows the addresss lines MSB to the right (it would work better if it was MSB to the left).  Again, not a show stopper, but something to keep in mind when working all this out...

In that same table, there maybe an error at the intersection of "8K * 8" and A15.  The table shows X but I think it should be S.

[This is where I make a fool of myself] The biggest problem/error/call-it-what-you-will is the use of bold "BANK 1" and "BANK 2" at the top of each example.  This is just totally wrong because (for example) looking at "J9/J17", these are the address selectors for bank 1 and bank 2 respectivly.  More generally, jumpers for bank 1 and bank 2 are mixed up across each example.  The bold "Bank 1" and "Bank 2" just should not be there.

By way of a further demonstration of my ability to make a fool of myself, here's another one...  Just below the bold "Bank" text, there's an area called "Boundary (Bytes)".  I think this is "Boundary (Words)".  There are two reasons why I say this.  Firstly the board is advertised as being able to handle up to 1MB.  See the following link (pg. 52);

https://bitsavers.computerhistory.org/pdf/motorola/versados/MVMEVDOS_D2_VMEHwSwConf_May85.pdf

and as that table only shows up to 256K bytes a bank, you could only get 512K on the board.  Secondly, if we assume that the text "256K" is correct, then we only need A18 to decode each bank if we're talking about words (not bytes).

With all that ranting out of the way, here's how I worked out the base address jumper settings;

Say we want bank 1 to be at address $040000 and we're using 8 off 32K * 8 RAM devices which is 256K as previously stated.

Consider the "Memory Device Capacity" table.  Locate the row corrisponding to the device size you're using.  So for me, it's "A A A A S S X" which is better read reversed as follows "X S S A A A A".  Just to be clear, we're talking about;

Code: [Select]
A18 A17 A16 A15 A14 A13 A12
 X   S   S   A   A   A   A

What this means is that;
  • A15 - A12 should be connected to the memory devices (nothing for you to do unless you need to fix a hardware problem as I described above)
  • A17 & A16 are decoded on the PCB (nothing for you to do)
  • A18 needs setting on the Jumpers
Just to explain in a little more detail; the two S bits of the address enable one-of-four pairs of devices to be selected.  These are the four odd and even pairs of devices in each coloum on the PCB.

When I said "A18 needs setting on the jumpers", more accurately I should have said "A18 and above need setting on the jumpers".

Rather than consider all the jumpers in a big bad old mess of jumper-meyhem, just think about J9 & J8.  Use the functional desciption and diagram provided top left of pg.3 but ignore their settings and let's start with no jumpers fitted.

Don't fit any jumpers for address bits that contain either an S or A.

For all the high address bits that don't contain an S or A, you need to configure the bit pattern...  In our case we have (remembering that I want the base address to be $040000);

Code: [Select]
A23 A22 A21 A20 A19 A18 A17 A16 A15 A14 A13 A12
 0   0   0   0   0   1   0   0   0   0   0   0
Before moving to the next step, I want to talk about something else...  The three example address base configurations provided on pg.3 don't explain how much memory is on the board being configured.  I think it's 8K words. The reason for this is that so far we've only been talking about configuring J8 & J9.

We're about to start talking about J10 & J11.  It's simple; these two jumper blocks are a bit-flip of J8 & J9 EXCEPT that you don't fit any jumpers for addresses within the block.  Reviewing the three example settings, we can see that in all of them, the bit-flip rule works for all the jumpers apart from the bottom two bits.  That's why I think the bank is 8K words wide.

Important  I don't know if this bit-flip guide is correct; it's just what I observe looking at the supplied information.

So coming back to our example and using the bit pattern above, here's all four jumper settings (1 = fit)

Here's the block base address;
Code: [Select]
J9 (don't forget that 12 does not count; it's GND)
12 10 08 06 04 02
 0  0  0  0  0  0

J8
14 12 10 08 06 04 02
 1  0  0  0  0  0  0

Now here's the block base address bit-flipped BUT ONLY FOR BITS OUTSIDE THE RANGE OF THE BLOCK

Code: [Select]
J11 (Don't forget the 12 does not count:  it's GND)
12 10 08 06 04 02
 0  1  1  1  1  1

J10
14 12 10 08 06 04 02
 0  0  0  0  0  0  0

OK.  So that's block 1 sorted.  Moving on to block 2, we want a base address of $080000.  Here's the settings without the woffle;

Code: [Select]
J17
12 10 08 06 04 02
 0  0  0  0  0  1

J16
14 12 10 08 06 04 02
 0  0  0  0  0  0  0

J19
12 10 08 06 04 02
 0  1  1  1  1  0

J18
14 12 10 08 06 04 02
 1  0  0  0  0  0  0
There's one final step.  All the above is "address bit pattern" friendly not "PCB layout" friendly.  Here's the same information as above but turned around to make transcribing to the PCB jumpers easier;

Code: [Select]
J8                      J9
 0 0 0 0 0 0 1           0 0 0 0 0 0

J10                     J11
 0 0 0 0 0 0 0           1 1 1 1 1 0
 
J16                     J17
 0 0 0 0 0 0 0           1 0 0 0 0 0
 
J18                     J19
 0 0 0 0 0 0 1           0 1 1 1 1 0

The MVME110Bug program I'm using has a Block Test (BT) function.  Using this shows errors with repeatable faults which is discouraging to say the least.

However if I change the boundaries of the BT function (i.e. Different start and end addresses that still include the "faulty" address from above), the fault goes away.

As an aside, other bug commands don't work, so either there's something wrong with the code or my card; not sure which!

Furthermore, I've written my own memory test program which is fairly simple, but it runs without error for days.  I am currently improving this to check that if I assert a single bit in the entire memory block, then only that very bit is high; all the rest are low.  Right now, the program only checks that it's possible to write / read 00 and FF to every location using byte or word accesses.  Shown below for information, sorry if coding style makes you weep :).

Code: [Select]
; Simple memory test.  Tests 64K byte blocks of RAM.
; Assumes code running on a MVME110 with 110-Bug Version 4.1
; There are four tests herein;
;   write-read $00 using byte access
;   write-read $FF using byte access
;   write-read $0000 using word access
;   write-read $FFFF using word access

; You can set the number of 64K byte blocks to test using "blocks"
; You can repeat all the above tests a set number of times using "repeats"


; D Waine 9/05/24

codeStart   equ             $1000           ; Start of this routine
ramStart    equ             $40000          ; Base addresss of RAM to test
blocks      equ             $8              ; Number of 64K blocks to test
repeats     equ             $2

            org             codeStart

            move.l          #$2000,A7       ; Init the stack
           
; Output welcome string
            move.l          #testStart,A5
            move.l          #testEnd,A6
            trap            #15
            dc.w            2

; Set up a counter for number of repeats of all tests to do
            move.l          #repeats,D1
            sub.l           #1,D1           ; Make loop count correct for dbra
            move.l          #0,D0           ; Counts number of times done all tests

bigLoop
           
; Simple all zeros memory write/read test using byte access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
block00BLoop
            move.l          #$ffff,D2

test00BLoop move.b          #$00,(A0)       ; write 00
            move.b          (A0)+,D4        ; Read test byte
            cmpi.b          #$00,D4         ; test for non zero
            bne             errIn00BTest    ; If byte read back in <>0, we have an error
            dbra            D2,test00BLoop
            dbra            D3,block00BLoop
 
; Simple all bits set memory write/read test using byte access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
blockFFBLoop
            move.l          #$ffff,D2

testFFBLoop move.b          #$ff,(A0)       ; write FF
            move.b          (A0)+,D4        ; Read test byte
            cmpi.b          #$ff,D4         ; test for non match
            bne             errInFFBTest    ; If byte read back in <>0, we have an error
            dbra            D2,testFFBLoop
            dbra            D3,blockFFBLoop
 
; Simple all zeros memory write/read test using word access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
block00WLoop
            move.l          #$7fff,D2       ; Becausee we're working on words, we only need $8000 loops

test00WLoop move.w          #$0000,(A0)     ; write 00
            move.w          (A0)+,D4        ; Read test byte
            cmpi.w          #$0000,D4       ; test for non zero
            bne             errIn00WTest    ; If word read back in <>0, we have an error
            dbra            D2,test00WLoop
            dbra            D3,block00WLoop

; Simple all bits set memory write/read test using word access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
blockFFWLoop
            move.l          #$7fff,D2       ; Becausee we're working on words, we only need $8000 loops

testFFWLoop move.w          #$ffff,(A0)     ; write FFFF
            move.w          (A0)+,D4        ; Read test byte
            cmpi.w          #$ffff,D4       ; test for non zero
            bne             errInFFWTest    ; If word read back in <>0, we have an error
            dbra            D2,testFFWLoop
            dbra            D3,blockFFWLoop

; Bump the test repeats counter and print it out
            add.l           #1,D0           ; Bump the test counter
           
            move.l          #testStart,A5   ; Point at RAM buffer to print D0
            bsr             bin2Asc32Bits
            move.l          A5,A6
            move.l          #testStart,A5
            trap            #15
            dc.w            2

; Go round for another repeat if we need to
            dbra            D1,bigLoop


; Print bye bye message
            move.l          #byeStart,A5
            move.l          #byeEnd,A6
            trap            #15
            dc.w            2

; Return to 110Bug
exitToBug   trap            #15
            dc.w            0

errIn00BTest
            move.l          #err00BStart,A5
            move.l          #err00BEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errInFFBTest
            move.l          #errFFBStart,A5
            move.l          #errFFBEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errIn00WTest
            move.l          #err00WStart,A5
            move.l          #err00WEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errInFFWTest
            move.l          #errFFWStart,A5
            move.l          #errFFWEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errInBitTestNonZero
            move.l          #errBit1Start,A5
            move.l          #errBit1End,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errInBitTestBitPattern
            move.l          #errBit2Start,A5
            move.l          #errBit2End,A6
            trap            #15
            dc.w            2
            bra             exitToBug

err00BStart dc.b            "Error in all zero byte access test, exiting to MVME110-BUG"
err00BEnd   dc.b            00
            dc.b            $0d,$0a

errFFBStart dc.b            "Error in all bits set byte access test, exiting to MVME110-BUG"
errFFBEnd   dc.b            00
            dc.b            $0d,$0a

err00WStart dc.b            "Error in all zero word access test, exiting to MVME110-BUG"
err00WEnd   dc.b            00
            dc.b            $0d,$0a

errFFWStart dc.b            "Error in all bits set word access test, exiting to MVME110-BUG"
errFFWEnd   dc.b            00
            dc.b            $0d,$0a

errBit1Start
            dc.b            "Error in bit test: location <>0, exiting to MVME110-BUG"
errBit1End  dc.b            00
            dc.b            $0d,$0a

errBit2Start
            dc.b            "Error in bit test: wrong bit pattern, exiting to MVME110-BUG"
errBit2End  dc.b            00
            dc.b            $0d,$0a

testStart   dc.b            'MVME211 Test program', $0d, $0a, 'D. Waine 12/05/24 Version 0.1'
testEnd     dc.b            00
            dc.b            $0d,$0a

byeStart    dc.b            "Exiting to MVME110-BUG"
byeEnd      dc.b            00
            dc.b            $0d,$0a
           

; Series of routines to convert D0 from binary to ASCII which is stored at (A5).  Bump
; A5 before we return.  The first routine is the core; all the others just rotate the nibble
; we're currently considering into the correct place
            align           2
bin2Asc4Bits
            move.w          D0,-(A7)        ; Save D0
            and.l           #$0F,D0         ; remove everything above the bottom 4 bits
            add.b           #$30,D0         ; Turn into ASCII
            cmpi.b          #$3A,D0         ; Is result greater than "9"?
            bmi.s           lessThanA
            add.b           #7,D0           ; hex over 9 look like a letter
lessThanA   move.b          D0,(A5)+        ; Store result in ASCII buffer
            move.w          (A7)+,D0        ; Restore D0
            rts

bin2Asc8Bits
            move.l          D0,-(A7)        ; Save the whole of D0
            ror.l           #4,D0           ; Get the high part of the byte into the bottom
            bsr             bin2Asc4Bits    ; And convert it
            move.l          (A7),D0         ; Recover the number without moving the stack
            bsr             bin2Asc4Bits
            move.l          (A7)+,D0       
            rts

bin2Asc16Bits
            move.l          D0,-(A7)
            ror.l           #8,D0           ; Get the hi byte in the lo byte
            bsr             bin2Asc8Bits    ; Convert what was the hi byte of the word
            rol.l           #8,D0           ; Restore the lo byte to the correct place
            bsr             bin2Asc8Bits
            move.l          (A7)+,D0
            rts
           
bin2Asc32Bits
            move.l          D0,-(A7)
            swap            D0              ; Get the hi word in the lo part (but save the lo part)
            bsr             bin2Asc16Bits
            swap            D0
            bsr             bin2Asc16Bits
            move.l          (A7)+,D0
            rts

            end             codeStart

As previously advised, I'm sure that there will be errors/misunderstandings with the above.  I'd appreciate any observations/corrections.
« Last Edit: May 20, 2024, 03:13:28 pm by LittleFrog »
Dave
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #11 on: May 24, 2024, 06:38:12 pm »
Hi

Just wanted to finish the MVME211 memory card configuration and test topic off.....

Turns out that I am so stupid, I did not follow my own instructions and effectivly I mis-configured the hot-wiring of pin 1 of the RAM chips.  When I went through the instructions in my last mail slowly, I realised that I'd made a mistake and when this was rectified, the MVME110-Bug memory test (BT) and my memory test program both run fine;

Code: [Select]
MVME110  4.1> bt 40000 bfffe
Physical Address=00040000 000BFFFE

MVME110  4.1> bt 40000 bfffe
Physical Address=00040000 000BFFFE

MVME110  4.1> bt 40000 bffffe
Physical Address=00040000 000BFFFE


My memory test is not very good but here's the final version which includes the ability to set a single walking bit that works its way through the whole of the test area checking that the rest of RAM is still $0000.  Right now, I JMP over this part of the test because is takes a couple of days to run.  Anyway it works fine now that I fixed my self-induced error.

Code: [Select]
; Walking bit memory test.  Program clears the test area to $0000 and then sets
; a single bit in the test word and checks that the whole of the rest of the test
; area is $0000 (apart from the test location of course!).

; I've left in some simpler memory tests too... These were useful to find simple
; errors quickly.

; D Waine 24/05/24

; Program assumes that there are a number of 64K blocks to check (8 in my case)
; and then the program repeats a number of times (2 typically)

; The source has 4 simple memory tests which are currently jumped over to get to
; the walking bit test more quickly.

codeStart   equ             $1000           ; Start of this routine
ramStart    equ             $40000
blocks      equ             $7              ; Number of 64K blocks to test
repeats     equ             2

            org             codeStart
            move.l          #$2000,A7       ; Init the stack

; Output welcome string
            move.l          #testStart,A5
            move.l          #testEnd,A6
            trap            #15
            dc.w            2

; Set up a counter for number of repeats of all tests to do
            move.l          #repeats,D1
            sub.l           #1,D1           ; Make loop count correct for dbra
            move.l          #0,D0           ; Counts number of times done all tests

bigLoop         
; Simple all zeros memory write/read test using byte access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
block00BLoop
            move.l          #$ffff,D2

test00BLoop move.b          #$00,(A0)       ; write 00
            move.b          (A0)+,D4        ; Read test byte
            cmpi.b          #$00,D4         ; test for non zero
            bne             errIn00BTest    ; If byte read back in <>0, we have an error
            dbra            D2,test00BLoop
            dbra            D3,block00BLoop
 
; Simple all bits set memory write/read test using byte access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
blockFFBLoop
            move.l          #$ffff,D2

testFFBLoop move.b          #$ff,(A0)       ; write FF
            move.b          (A0)+,D4        ; Read test byte
            cmpi.b          #$ff,D4         ; test for non match
            bne             errInFFBTest    ; If byte read back in <>0, we have an error
            dbra            D2,testFFBLoop
            dbra            D3,blockFFBLoop
 
; Simple all zeros memory write/read test using word access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
block00WLoop
            move.l          #$7fff,D2       ; Becausee we're working on words, we only need $8000 loops

test00WLoop move.w          #$0000,(A0)     ; write 00
            move.w          (A0)+,D4        ; Read test byte
            cmpi.w          #$0000,D4       ; test for non zero
            bne             errIn00WTest    ; If word read back in <>0, we have an error
            dbra            D2,test00WLoop
            dbra            D3,block00WLoop

; Simple all bits set memory write/read test using word access
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra
blockFFWLoop
            move.l          #$7fff,D2       ; Becausee we're working on words, we only need $8000 loops

testFFWLoop move.w          #$ffff,(A0)     ; write FFFF
            move.w          (A0)+,D4        ; Read test byte
            cmpi.w          #$ffff,D4       ; test for non zero
            bne             errInFFWTest    ; If word read back in <>0, we have an error
            dbra            D2,testFFWLoop
            dbra            D3,blockFFWLoop

            jmp             missOutTests
           
; Use word access to write one bit set at a time in the whole of the memory under test and check that only
; that one bit is actually set.  Test happens in a number of steps as follows;
; 1 - Set every word in memory to 0000
; 2 - Initialise a "one bit in one word" loop
; 3 - Set the bit in the word under test
; 4 - Read the whole of memory checking that everything is zero apart from the word under test and that should
;     have exacty the correct bit set
; 5 - Bump the bit under test
; 6 - When we've done all 16 bits, step to the next word
; 7 - Repeat until all words under test have been checked
; The program loops so that this test can be repeated as required

;   Initalise every word in the memory under test to 0000
start       move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3           ; Make loop count correct for dbra

initBlockLoop
            move.l          #$7fff,D2       ; Because we're working on words, we only need $8000 loops

initWordLoop
            move.w          #$0000,(A0)+    ; write 00 and bump the pointer by 2 (it's a word remember!)
            dbra            D2,initWordLoop
            dbra            D3,initBlockLoop

;   Init the "one bit set" loop which requires just the same loop as above but we also set up the one-bit-set
;   and the address under test
            move.l          #ramStart,A0
            move.l          #blocks,D3
            sub.l           #1,D3               ; Make loop count correct for dbra

testBlockLoop
            move.l          #$7fff,D2           ; Because we're working on words, we only need $8000 loops

chkNxtAddr  move.l          #$0001,D1           ; D1 holds the bit we're testing currently.  If you make this
                                                ; $8000 then the test does not try all 16 bits... Just the MSB
                                                ; which speed it up by 16*

;   Set the test bit and then read the whole of memory checking that it's zero unless we're on the
;   test word, in which case, test that it's the correct bit (i.e. The contents of D1)
testBitWordLoop           
            move.w          D1,(A0)             ; place the current test word in memory           
            move.l          #ramStart,A1        ; Read the whole of memory under test
            move.l          #blocks,D4
            sub.l           #1,D4

chkBlockLoop
            move.l          #$7fff,D5
chkMemLoop
            move.w          (A1),D6             ; Get the contents of the memory location we're testing
            cmp.l           A0,A1               ; Are we at the test memory location?
            beq.s           testLocation
            cmpi.w          #0000,D6            ; Not at test location so check memory is zero
            beq             nextBitPattern
            bsr             errInBitTestNonZero
           
nextBitPattern
            add.l           #2,A1               ; point at next memory location we're checking
            dbra            D5,chkMemLoop
            dbra            D4,chkBlockLoop

            asl.w           #1,D1               ; Move to next bit pattern
            bcs.s           nextAddress         ; If we've done all the bits, goto next address to test
            bra             testBitWordLoop

nextAddress move.w          #0000,(A0)+         ; Repair the test word and point at next address
;            jmp             testExit
            bsr             printAddress        ; Print the address we've just tested
            bra             chkNxtAddr     
           
            dbra            D2,testBitWordLoop
            dbra            D3,testBlockLoop
            bra             nextRepeat

testLocation
            cmp.w           D6,D1               ; At test location so check against bit pattern
            beq             nextBitPattern
            bsr             errInBitTestBitPattern
            bra             nextBitPattern

missOutTests
; Bump the test repeats counter and print it out
nextRepeat  add.l           #1,D0           ; Bump the test counter
           
            move.l          #testStart,A5   ; Point at RAM buffer to print D0
            bsr             bin2Asc32Bits
            move.l          A5,A6
            move.l          #testStart,A5
            trap            #15
            dc.w            2

; Go round for another repeat if we need to
            dbra            D1,bigLoop

testExit
; Print bye bye message
            move.l          #byeStart,A5
            move.l          #byeEnd,A6
            trap            #15
            dc.w            2

; Return to 110Bug
exitToBug   trap            #15
            dc.w            0

errIn00BTest
            move.l          #err00BStart,A5
            move.l          #err00BEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errInFFBTest
            move.l          #errFFBStart,A5
            move.l          #errFFBEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errIn00WTest
            move.l          #err00WStart,A5
            move.l          #err00WEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errInFFWTest
            move.l          #errFFWStart,A5
            move.l          #errFFWEnd,A6
            trap            #15
            dc.w            2
            bra             exitToBug

errInBitTestNonZero
            move.l          #errBit1Start,A5
            move.l          #errBit1End,A6
            trap            #15
            dc.w            2
            bsr             printRegs
            rts

errInBitTestBitPattern
            move.l          #errBit2Start,A5
            move.l          #errBit2End,A6
            trap            #15
            dc.w            2
            bsr             printRegs
            rts

; Print the contents of A0 which is the address being tested
printAddress
            move.l          D0,-(A7)
            move.l          A0,D0
            move.l          #testAdEnd,A5   ; Point at place to store ASCII
            bsr             bin2Asc32Bits
            move.l          A5,A6           ; Point at end of message
            move.l          #testAdStart,A5
            trap            #15
            dc.w            2           
            move.l          (A7)+,D0
            rts

; Print the important registers
;   D0      Repeat counter              Word
;   A0      Address being tested        Long
;   D1      Test pattern                Word
;   A1      Address where anomoly found Long
;   D6      Data found at anomoly       Word
; Notice that the Bin-> Ascii converter drops the number into the correct
; place in the string and then prints it out

printRegs   move.l          D0,-(A7)        ; Save on stack
            move.l          D6,-(A7)
    ; Print D0
            move.l          #repeatEnd,A5   ; Point at place to store ASCII
            bsr             bin2Asc16Bits
            move.l          A5,A6           ; Point at end of message
            move.l          #repeatStart,A5
            trap            #15
            dc.w            2
    ; Print A0
            move.l          A0,D0
            move.l          #testAdEnd,A5   ; Point at place to store ASCII
            bsr             bin2Asc32Bits
            move.l          A5,A6           ; Point at end of message
            move.l          #testAdStart,A5
            trap            #15
            dc.w            2
    ; Print D1
            move.w          D1,D0
            move.l          #testPtEnd,A5   ; Point at place to store ASCII
            bsr             bin2Asc16Bits
            move.l          A5,A6           ; Point at end of message
            move.l          #testPtStart,A5
            trap            #15
            dc.w            2
    ; Print A1
            move.l          A1,D0
            move.l          #erAdEnd,A5   ; Point at place to store ASCII
            bsr             bin2Asc32Bits
            move.l          A5,A6           ; Point at end of message
            move.l          #erAdStart,A5
            trap            #15
            dc.w            2
    ; Print D6
            move.l          (A7)+,D0        ; Get D6 back into D0
            move.l          #erDtEnd,A5     ; Point at place to store ASCII
            bsr             bin2Asc16Bits
            move.l          A5,A6           ; Point at end of message
            move.l          #erDtStart,A5
            trap            #15
            dc.w            2

            move.l          (A7)+,D0        ; Restore from stack
            rts
           
repeatStart dc.b            "Repeat counter "
repeatEnd   dc.b            "****"
            dc.b            $0d,$0a

testAdStart dc.b            "Test address   "
testAdEnd   dc.b            "********"
            dc.b            $0d,$0a

testPtStart dc.b            "Test pattern   "
testPtEnd   dc.b            "****"
            dc.b            $0d,$0a

erAdStart   dc.b            "Error address  "
erAdEnd     dc.b            "********"
            dc.b            $0d,$0a

erDtStart   dc.b            "Error data     "
erDtEnd     dc.b            "****"
            dc.b            $0d,$0a
           
err00BStart dc.b            "Error in all zero byte access test, exiting to MVME110-BUG"
err00BEnd   dc.b            00
            dc.b            $0d,$0a

errFFBStart dc.b            "Error in all bits set byte access test, exiting to MVME110-BUG"
errFFBEnd   dc.b            00
            dc.b            $0d,$0a

err00WStart dc.b            "Error in all zero word access test, exiting to MVME110-BUG"
err00WEnd   dc.b            00
            dc.b            $0d,$0a

errFFWStart dc.b            "Error in all bits set word access test, exiting to MVME110-BUG"
errFFWEnd   dc.b            00
            dc.b            $0d,$0a

errBit1Start
            dc.b            "Error in bit test: location <>0"
errBit1End  dc.b            00
            dc.b            $0d,$0a

errBit2Start
            dc.b            "Error in bit test: wrong bit pattern"
errBit2End  dc.b            00
            dc.b            $0d,$0a

testStart   dc.b            'MVME211 memory test', $0d, $0a, 'D. Waine 24/05/24 Version 0.2'
testEnd     dc.b            00
            dc.b            $0d,$0a

byeStart    dc.b            "Exiting to MVME110-BUG"
byeEnd      dc.b            00
            dc.b            $0d,$0a
           

; Series of routines to convert D0 from binary to ASCII which is stored at (A5).  Bump
; A5 before we return.  The first routine is the core; all the others just rotate the nibble
; we're currently considering into the correct place
            align           2
bin2Asc4Bits
            move.w          D0,-(A7)        ; Save D0
            and.l           #$0F,D0         ; remove everything above the bottom 4 bits
            add.b           #$30,D0         ; Turn into ASCII
            cmpi.b          #$3A,D0         ; Is result greater than "9"?
            bmi.s           lessThanA
            add.b           #7,D0           ; hex over 9 look like a letter
lessThanA   move.b          D0,(A5)+        ; Store result in ASCII buffer
            move.w          (A7)+,D0        ; Restore D0
            rts

bin2Asc8Bits
            move.l          D0,-(A7)        ; Save the whole of D0
            ror.l           #4,D0           ; Get the high part of the byte into the bottom
            bsr             bin2Asc4Bits    ; And convert it
            move.l          (A7),D0         ; Recover the number without moving the stack
            bsr             bin2Asc4Bits
            move.l          (A7)+,D0       
            rts

bin2Asc16Bits
            move.l          D0,-(A7)
            ror.l           #8,D0           ; Get the hi byte in the lo byte
            bsr             bin2Asc8Bits    ; Convert what was the hi byte of the word
            rol.l           #8,D0           ; Restore the lo byte to the correct place
            bsr             bin2Asc8Bits
            move.l          (A7)+,D0
            rts
           
bin2Asc32Bits
            move.l          D0,-(A7)
            swap            D0              ; Get the hi word in the lo part (but save the lo part)
            bsr             bin2Asc16Bits
            swap            D0
            bsr             bin2Asc16Bits
            move.l          (A7)+,D0
            rts

            end             codeStart


Thanks again to MarcoPolo for the configuration information that unlocked the way forward.
Dave
 

Online marcopolo

  • Regular Contributor
  • *
  • Posts: 164
  • Country: fr
  • F4LIG
    • Retronik
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #12 on: May 24, 2024, 06:51:53 pm »
It's time to test the MVME320  :)
My Archives (68K, Old logic, SSB radio): marc.retronik.fr
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #13 on: May 24, 2024, 07:30:54 pm »
Quote
It's time to test the MVME320  :)

Yes.... 

I've got three commands to play with IOT, IOP & IOC.

Some great news is that in the past (pre-off board RAM), both the IOT & IOP commands just hung up until the red "Fail" LED came on. Now all three commands respond with sensible configuration options.  I'm going to go quiet now while I work out what works and what does not.

I have two little utilities to help me....  They're not amazingly written but here they are for your interest...

Both make use of the fact that I'm using a terminal server to talk to the MVME110 serial port.  The TS has Ethernet on one end and RS232 on the other.  It's actually this;

https://www.amazon.co.uk/dp/B07G5P4CPR?psc=1&ref=ppx_yo2ov_dt_b_product_details

The programs are written in Python 3.

RAM variables
It would be useful to know what the various RAM resident variables in the memory of the MVME110 are set to.  I have the source code from BitSavers and so if I could find the memory location of one of them, then I could work out the memory location of the rest of them from that hint. Knowing that, I could populate a list of their current state by doing a MD of the correct memory range....

I worked out that a variable called "ENDON" is stored at memory location $00060E.  This is actually fairly easy to do by looking at some source that uses that variable and doing a search of the EPROM for the correct byte sequence.  You get the byte sequence by quickly assembling that part of the source.

Anyway you put the hint in the first line of a text file then follow that with the source that describes memory allocation like this;

Code: [Select]
ENDON 60E
IPCNUM   DS.W      1                   CONTROLLER NUMBER
DRVNUM   EQU       IPCNUM+1            DEVICE NUMBER
 
         DS.W      0                   ..force word boundry
CMD      DS.B      10                  IMAGE OF 6 to 10 BYTE COMMAND
BPS      DS.W      1                   BYTES PER SECTOR
SECNUMW  DS.W      1                   .W NUMBER OF SECTORS TO TRANSFER
 
BD1SEC   DS.L      1                   BOOT-DUMP DISK 1ST BLOCK ADDRESS
BDNSEC   DS.W      1                   BOOT-DUMP DISK NUMBER OF BLOCKS
BO1SEC   DS.L      1                   BOOT-LOAD DISK 1ST BLOCK ADDRESS
BONSEC   DS.W      1                   BOOT-LOAD DISK NUMBER OF BLOCKS
BOMEMA   DS.L      1                   BOOT-LOAD MEMORY ADDRESS
 
TEMP_L   DS.L      1                   Temporary storage where Vol ID is saved
USERREGS DS.L      2                   Temp. storage for reg. A5 & A6
USERTEXT DS.B      26                  Reserve space for boot message
 
BHIND    DS.B      1                   BOOT AND HALT FLAG
CTYPE    DS.B      1                   CONTROLLER TYPE INDICATOR
 
         DS.W      0                   ...FORCE WORD BOUNDRY
DISKSIZ  DS.L      1                   DISK SPACE REMAINING AFTER DUMP
CTYPENOW DS.L      1                   CONTROLLER TYPE PRESENTLY IN USE
CTYPE4   DS.L      1                   CTYPE*4 USED AS ADDR. OFFSET IN JMP TABL
CONTYPE  DS.L      1                   IPCNUM 0 CONTROLLER TYPE DEFAULT
         DS.L      1                   IPCNUM 1 CONTROLLER TYPE DEFAULT
         DS.L      1                   IPCNUM 2 CONTROLLER TYPE DEFAULT
         DS.L      1                   IPCNUM 3 CONTROLLER TYPE DEFAULT
         DS.L      1                   IPCNUM 4 CONTROLLER TYPE DEFAULT
SCRATCH  DS.L      1                   OFFBOARD RAM $1K SCRATCH PAD
CONFDAT  DS.L      1                   POINTER TO CONFIGURATION DATA
ENDON    DS.L      1                   END OF ON BOARD MEMORY
ENDOFF   DS.L      1                   END OF OFF BOARD MEMORY
HARDWRE  DS.L      1                   POINTER TO HARDWARE FROM 'GETVOLID'
OFFBLKS  DS.L      1                   NUMBER OF BLOCKS OF OFFBOARD RAM
OFFDUMP  DS.L      1                   NUMBER OF OFFBOARD RAM DUMPED
ONBLKS   DS.L      1                   NUMBER OF BLOCKS OF ONBOARD RAM
ONDUMP   DS.L      1                   NUMBER OF ONBOARD RAM DUMPED
STARTOFF DS.L      1                   START OF OFF BOARD MEMORY (0 IF NONE)
GAPBLKS  DS.L      1                   SIZE OF THE GAP BET. ONBD & OFFBD RAM
MSIZED   DS.B      1                   "MEMORY SIZED" INDICATOR SWITCH
****************************************************
*       - PARAMETERS USED IN 'IOP' COMMAND -       *
****************************************************
 
ZAPRW    DS.W 1  READ OR WRITE SWITCH (INITIALIZED SETS TO "R")
ZAPARGS  DS.L 0  PARMS USED TO LOAD VARIABLES TO PACKET IN "ZAP" COMMAND.
ZAPSCNT  DS.L 1  NUMBER OF BLOCKS TO BE OR READ/WRITTEN.
ZAPMEM   DS.L 1  I/O ADDRESS.
ZAP1STS  DS.L 1  STARTING BLOCK NUMBER.

Then run this program;
Code: [Select]
# Program uses extracts from assembler source listings and a hint address to load up current
# contents memory/symbol contents from an MVME110.  Here's an example;

# ENDON 60E
# IPCNUM   DS.W      1                   CONTROLLER NUMBER
# DRVNUM   DS.W      10                  DEVICE NUMBER
# ENDON    DS.L      1                   Holds end of local memory

# The source listing typically contains assembler directives like DC.B or DS.W etc.
# The hint address can refer to any of the symbols in the source and should be the first record in
# the source listing and is of the form "symbol <SPACE> address"
# The program then works out what memory to read to get all the current values from the MVME110
# Comms with the MVME110 re via a Terminal Server

# D. Waine 13/05/24

# In order that this program function, you need to have the TS and the MVME110 switched on (!)
# then start a terminal session using puTTY to the TS.  Run this program, providing the filename
# of the source file (without extension) on the command line.  This program assumes that the file
# extension is .map. For example;

# mvme110RAMRead 320 (to read the file called "320.map")

import sys
import os
import socket
from time import sleep

# Col widths for fancy output of finished table
colWidth = [4, 6, 10, 6, 10, 20, 50]
colTitles = ['Len', 'Adrs', 'Label', 'Op', 'Reps', 'Value', 'Comment']

def ascii2Int (value):
    return (int (value, 16))

def fancyRow (r):
    # Make the supplied list, which contains a row in the output table, nice for printing
    outputString = ''
    for ptr in range (0, len (r)):
        if ptr == 0:
            # Format the length field
            contents = str (r [ptr])
        elif ptr == 1:
            # Format the address field allowing for a title or actual number
            if isinstance (r [ptr], str) == True:
                contents = r [ptr]
            else:
                contents = '{:04X}'.format(r [ptr])
        elif ptr == 2:
            # Format the Label field
            contents = r [ptr]
        elif ptr == 3:
            # Format the Operation field
            contents = r [ptr]
        elif ptr == 4:
            # format the Repeats field
            contents = str (r [ptr])
        elif ptr == 5:
            # Format the value field
            contents = r [ptr]
        elif ptr == 6:
            # Format the comment field
            contents = r [ptr]
        else:
            print ('Error in fancy formatting')
        # Add trailing spaces to all fields
        fieldWidth = colWidth [ptr]
        contents = contents + ' ' * (fieldWidth - len (contents))
        # Stop the contents being too long
        if len (contents) > (fieldWidth - 1):
            contents = contents [0:fieldWidth - 1] + ' '
        outputString = outputString + contents
    return (outputString)
   
# Location of the TS on the LAN
terminalAddress = '192.168.0.3'
terminalPort = 8234

if len (sys.argv) != 2:
    print ('Incorrect number of arguments.  You need to supply the input .map file without an extension')
    sys.exit (1)

filename = sys.argv [1]
fileExtension = '.map'
inputFile = filename + fileExtension

lineCounter = 0
outputCounter = 0

# Open the input file
print ('Opening source symbol file: ', inputFile)
with open(inputFile) as inFile:
    print ('Opening output stream to MVME110')
    sock = socket.socket()
    sock.connect((terminalAddress, terminalPort))
    print ('Connected')
    sleep (0.1)
    # Read the address hint, this contains two fields; the symbol and the address
    # Strip off Spaces and CR/LF.  Split the string into two at the space
    # Turn the address into an INT (from ASCII hex)
    # Do some error checking (bit crude!)
    hint = inFile.readline ()
    hint = hint.strip ()
    hint = hint.split ()
    hintSymbol = hint[0]
    hintAddress = hint [1]
    hintAddress = ascii2Int (hintAddress)
    if len (hintSymbol) < 3:
        print ('hint Symbol too short (it needs to be longer than 3 chars')
        exit (1)
    if hintAddress == 0:
        print ("hint address can't be zero")
        exit (1)
    print ('Using hint symbol:  ', hintSymbol)
    print ('Using hint address: ', hex(hintAddress))
   
    # Read the symbols and their definition a record at a time and load up a list of valid symbols
    table = []              # Valid records stored in here
    foundHint = False       # Gets set to true when we've found the hint symbol
   
    for inputLine in inFile:
        # Trim the input line of CR/LF but don't strip SPACE
        inputLine = inputLine.strip ('\n')
        inputLine = inputLine.strip ('\r')
        # Throw away lines that are not symbols but save valid lines to the table
        if len (inputLine.strip ()) == 0:
            pass
#            print ('Blank line')
        elif inputLine [0] == '*':
            pass
#            print ('Comment')
        elif inputLine [0] == ' ':
            pass
#            print ("First char can't be space")
        else:
            # Split the record into fields
            validRecord = inputLine.split ()
            # Depending on the assembler command, indicate how many bytes the record
            # will require.
            if validRecord [1] == 'DS.B':
                size = (1 * int (validRecord [2]))
            elif validRecord [1] == 'DS.W':
                size = (2 * int (validRecord [2]))
            elif validRecord [1] == 'DS.L':
                size = (4 * int (validRecord [2]))
            else:
                print ("Warning, can't update offset: ", inputLine)
                size = 0

            # Spot the hint symbol (or not!)
            if validRecord [0] == hintSymbol:
                # If we've already found the hint symbol, then we've found another one
                # so error
                if foundHint == True:
                    print ('Found multiple hint symbols which this program cannot handle')
                    exit (1)
                # Append a new entry to the table to include the size and hint address
                table = table + [[size] + [hintAddress] + validRecord]
                foundHint = True
            else:
                # This record we're appending ot the list does not have the hint address
                # so just make it zero for now (it gets loaded later)
                table = table + [[size] + [0] + validRecord]
           
    # Little bit of error checking; the rest of the program will only work if we've
    # got a valid hint address
    if foundHint == False:
        print ("Didn't find match between hint symbol and symbol table entry")
        exit (1)

    # So the table is basically built, now we have to load up the correct addresses
   
    # Go DOWN the table working out actual addresses at offsets AFTER the hint
    foundAddress = False
    for row in range (0, len (table)):
        # Search for the row containing the hint address
        if table [row][1] != 0:
            foundAddress = True
        # As long as we've found the hint address and we're not at the first row of the table
        # or the row containing the hint, we can work out what the address should be
        if (foundAddress == True) and (row > 0) and (table [row][1] == 0):
            # It's the address of the previous row plus the previous row's length
            table [row][1] = table [row - 1][1] + table[row - 1][0]
   
    # More error checking; this should not happen!
    if foundAddress == False:
        print ('Could not find hint address in table')
        exit (1)
       
    # Do the reverse; working from the end of the table back UP the table to row zero
    foundEmpty = False
   
    # The loop counter goes up but...
    for pointer in range (0, len (table)):
        # The row we want to look at is from the end back over.  The -1 is required because
        # len() returns the number of rows NOT the index of the last row
        row = len (table) - pointer - 1
       
        if table [row] [1] == 0:
            foundEmpty = True
        # Update the address if we've already found an empty address and we're not looking
        # at the last row in the table
        if (foundEmpty == True) and (row < (len(table) - 1)):
            # The address is the next entry address minus the next entry length
            table [row][1] = table [row + 1][1] - table [row][0]
   
    # We can now work out the addressses we need and get them in a form useful for forming
    # the MVME110 command [2:] removes the leading 0x supplied by hex()
    startAddress = hex(table [0][1]) [2:]
    endAddress = hex (table [len (table) - 1][1]) [2:]
    # The number of bytes is the address of the last record minus the address of the first record
    # I add a bit to this to make sure we get enough (needs a close look at!)
    length = hex ((table [len (table) - 1][1]) - (table [0][1]) + 16) [2:]
    print ('Starting address that we need: ', startAddress)
    print ('Ending address that we need  : ', endAddress)
    print ('Length                       : ', length)
   
    # Form the command to be sent to the MVME110 and send it
    cmdToSend = 'MD ' + startAddress + ' ' + length
    sock.send ((cmdToSend + '\r').encode())
   
    # read in the response, building it up in charStream until we see the command prompt
    # Notice that we work with character strings and not byte strings.  This is just to make
    # processing easier.
    charStream = ''
    while  'MVME110  4.1>' not in charStream:
        # Read the input and convert from byte to char string
        chars = sock.recv (1).decode ()
        charStream = charStream + chars

    # Turn the massive string into a list
    response = charStream.split ('\r\n')   
   
    # Build a massive string containing only the ASCII byte values
    bytes = ''
    # Loop over list, missing out the echo-ed command and a pair of post-content lines
    for row in range (1, len (response) - 2):
        # For each row, strip off the address and trailing spaces.  This is done quite
        # carefully to ensure that there is always a space between byte values
        byteLine = (response [row])[10:59]
        bytes = bytes + byteLine
    # When we're complete, spilt the big string into a list of ASCII byte values
    byteList = bytes.split ()

    # Go through the table, incrementing the pointer with the length of each field
    # and using that pointer to grab the correct ASCII byte values
    pointer = 0
    for row in range (0, len (table)):
        # Get the field length and...
        fieldLength = table [row][0]
        # Use it to point at the end of the bytes we want to grab.  The start of the bytes
        # is the "pointer"
        fieldValue = (byteList [pointer:pointer + fieldLength])
        # Drop the new field into the list.  There's a lot going on here!  We re-create the content
        # of the current row to contain the first 5 fields (0 -> 4) and then join together the byte
        # values into a single string.  Finally we join together any trailing comments into a single
        # string
        table[row] = table [row][0:5] + [' '.join (fieldValue)] + [' '.join (table [row] [5:])]
        # Point at the next place in the ASCII byte value list
        pointer = pointer + fieldLength

    printableTitle = fancyRow (colTitles)
    print (printableTitle)
   
    for row in table:
        printableRow = fancyRow (row)
        print (printableRow)

    sock.close()
exit (0)

So from a W10 cmd session, run it like this;

Code: [Select]
C:\Users\dgwai\OneDrive\Documents\68k\68K VME Boards\dgwDevelopment>mvme110ramread 320
Opening source symbol file:  320.map
Opening output stream to MVME110
Connected
Using hint symbol:   ENDON
Using hint address:  0x60e
Warning, can't update offset:  DRVNUM   EQU       IPCNUM+1            DEVICE NUMBER
Starting address that we need:  5ae
Ending address that we need  :  63d
Length                       :  9f
Len Adrs  Label     Op    Reps      Value               Comment
2   05AE  IPCNUM    DS.W  1         00 00               CONTROLLER NUMBER
0   05B0  DRVNUM    EQU   IPCNUM+1                      DEVICE NUMBER
10  05B0  CMD       DS.B  10        00 00 00 00 00 00 0 IMAGE OF 6 to 10 BYTE COMMAND
2   05BA  BPS       DS.W  1         00 00               BYTES PER SECTOR
2   05BC  SECNUMW   DS.W  1         00 00               .W NUMBER OF SECTORS TO TRANSFER
4   05BE  BD1SEC    DS.L  1         00 00 00 00         BOOT-DUMP DISK 1ST BLOCK ADDRESS
2   05C2  BDNSEC    DS.W  1         00 00               BOOT-DUMP DISK NUMBER OF BLOCKS
4   05C4  BO1SEC    DS.L  1         00 00 00 00         BOOT-LOAD DISK 1ST BLOCK ADDRESS
2   05C8  BONSEC    DS.W  1         00 00               BOOT-LOAD DISK NUMBER OF BLOCKS
4   05CA  BOMEMA    DS.L  1         00 00 00 00         BOOT-LOAD MEMORY ADDRESS
4   05CE  TEMP_L    DS.L  1         00 00 00 00         Temporary storage where Vol ID is saved
8   05D2  USERREGS  DS.L  2         00 00 00 00 00 00 0 Temp. storage for reg. A5 & A6
26  05DA  USERTEXT  DS.B  26        00 00 00 00 00 00 0 Reserve space for boot message
1   05F4  BHIND     DS.B  1         49                  BOOT AND HALT FLAG
1   05F5  CTYPE     DS.B  1         4E                  CONTROLLER TYPE INDICATOR
4   05F6  DISKSIZ   DS.L  1         53 41 53 35         DISK SPACE REMAINING AFTER DUMP
4   05FA  CTYPENOW  DS.L  1         53 41 53 38         CONTROLLER TYPE PRESENTLY IN USE
4   05FE  CTYPE4    DS.L  1         20 33 31 35         CTYPE*4 USED AS ADDR. OFFSET IN JMP TABL
4   0602  CONTYPE   DS.L  1         20 33 32 30         IPCNUM 0 CONTROLLER TYPE DEFAULT
4   0606  SCRATCH   DS.L  1         00 0B F0 00         OFFBOARD RAM $1K SCRATCH PAD
4   060A  CONFDAT   DS.L  1         00 00 00 00         POINTER TO CONFIGURATION DATA
4   060E  ENDON     DS.L  1         00 00 7F FF         END OF ON BOARD MEMORY
4   0612  ENDOFF    DS.L  1         00 0B FF FF         END OF OFF BOARD MEMORY
4   0616  HARDWRE   DS.L  1         00 FF B0 00         POINTER TO HARDWARE FROM 'GETVOLID'
4   061A  OFFBLKS   DS.L  1         00 00 08 00         NUMBER OF BLOCKS OF OFFBOARD RAM
4   061E  OFFDUMP   DS.L  1         00 00 00 00         NUMBER OF OFFBOARD RAM DUMPED
4   0622  ONBLKS    DS.L  1         00 00 00 80         NUMBER OF BLOCKS OF ONBOARD RAM
4   0626  ONDUMP    DS.L  1         00 00 00 00         NUMBER OF ONBOARD RAM DUMPED
4   062A  STARTOFF  DS.L  1         00 04 00 00         START OF OFF BOARD MEMORY (0 IF NONE)
4   062E  GAPBLKS   DS.L  1         00 00 03 80         SIZE OF THE GAP BET. ONBD & OFFBD RAM
1   0632  MSIZED    DS.B  1         01                  "MEMORY SIZED" INDICATOR SWITCH
2   0633  ZAPRW     DS.W  1         00 57               READ OR WRITE SWITCH (INITIALIZED SETS TO "R")
0   0635  ZAPARGS   DS.L  0                             PARMS USED TO LOAD VARIABLES TO PACKET IN "ZAP" C
4   0635  ZAPSCNT   DS.L  1         00 00 00 00         NUMBER OF BLOCKS TO BE OR READ/WRITTEN.
4   0639  ZAPMEM    DS.L  1         01 00 04 00         I/O ADDRESS.
4   063D  ZAP1STS   DS.L  1         00 00 00 00         STARTING BLOCK NUMBER.

C:\Users\dgwai\OneDrive\Documents\68k\68K VME Boards\dgwDevelopment>

Under the hood, the program has worked out the memory range it needs to read and then sent the MD command to the MVME110...  It then parses the response and pokes the correct response into the correct row of the output table.  What is exciting about this is that you can see "STARTOFF" & "ENDOFF"...  They have the correct values for the RAM board.  Exciting.

I'm going to use this program to check that when I do an IOT, I get the correct numbers poked into the variables you see near the bottom...

IOC command formatter

The IOC command needs a row of bytes assembling into RAM that represent the command to be sent to the MVME320.  You only attempt to key them in once and then you realise it's impossible to do without error.  So I have a configuration file like this which I built up by reading various documents on the ECA.
Code: [Select]
# Start loading the ECA as per MVME320 User Manual pg C-9
# Commands described pg 6-1
# Zap the buffer back to 00
bf BFF110 BFF170 00
# Zap the data buffer
bf B00000 b01000 00
# Fill the ECA
m BFF110
# Command code (Recalibrate to track 0) $00
01
# Main status $01
00
# Extended status (Should be 00 before command) $02
00
00
# Max retries $04
0a
# Actual retries $05
00
# DMA type $06
00
# Command options $07
00
# Buffer address (Hi word) $08
00
B0
# Buffer address (Lo word)
00
00
# Buffer length requested $0C
00
01
# Buffer length transferred $0E
00
00
# Cylinder number $10
00
00
# Head number
00
# Sector number
01
# Current cylinder position $14
00
02
# Reserved $16
00
00
00
00
00
00
00
00
00
00
# Pre index gap $20
00
# Post index gap
00
# Sync byte count
00
# Post ID gap
00
# Post data gap
36
# Address mark count
03
# Sector length code
01
# Fill byte
e5
# Reserved $28
00
00
00
00
00
00
# Drive type - Soft sectored, Hard disk with CRC $2E
03
# Number of surfaces $2F
04
# Sectors per track $30
0a
# Stepping rate $31
06
# Head settling time $32
46
# Head load time $33
46
# Seek type $34
02
# Reserved (Phase count) $35
00
# Low write current $36
00
50
# Precomp cylinder $38
00
50
# ECC remainder $3A
00
00
00
00
00
00
# Appended EEC remainder $40
00
00
00
00
00
00
# Reserved $46
00
00
00
00
# MVME320 working area $4A
00
00
00
00
00
00
00
00
00
00
00
00
# Reserved for the controller $56
0f
f0
# Get out of data entry mode
.
# Present a dump of the command
md BFF110 5f
# Actually send the command to the MVME320
# ioc 0,4

Then this program squirts the keystrokes down to the MVME110 Terminal Server and on to the board itself...

Code: [Select]
# Send a series of keystrokes to an MVME110 serial port via a terminal server connected
# on the LAN.  The keystrokes are held in a file, e.g. keystrokes.key

# D. Waine 27/04/24

# In order that this program function, you need to have the TS and the MVME110 switched on (!)
# then start a terminal session using puTTY to the TS.  Run this program and the
# key strokes will load.

import sys
import os
import socket
from time import sleep

# Location of the TS on the LAN
terminalAddress = '192.168.0.3'
terminalPort = 8234

if len (sys.argv) != 2:
    print ('Incorrect number of arguments.  You need to supply the input .key file without an extension')
    sys.exit (2)

filename = sys.argv [1]
fileExtension = '.key'
inputFile = filename + fileExtension

lineCounter = 0
outputCounter = 0

# Open the input file
print ('Openning input file: ', inputFile)
with open(inputFile) as inFile:
    print ('Openning output stream to MVME110')
    sock = socket.socket()
    sock.connect((terminalAddress, terminalPort))

    print ('Connected')
    sleep (0.1)
    # Read it a record at a time
    for line in inFile:
        # Trim the input line of CR/LF & any spaces
        inputLine = line.strip()
        # Bump the correct input record type counter
        lineCounter += 1
        if inputLine [0] != '#':
            sock.send ((inputLine + '\r').encode())
            sleep (0.1)
            outputCounter += 1
    sock.close()
print ('Input records: ', lineCounter)
print ('Sent records:  ', outputCounter)


The only bit that I've not explained is how to find the location in memory that IOC uses to form the ECA.  This is easy because the first time you run it, it shows you a hex dump of MOST (but not all!) the bytes in the ECA like this;

Code: [Select]
MVME110  4.1> ioc
                         DRIVE number=.......$00  ?
                    CONTROLLER number=.......$04  ?
Packet(s) at $000BF110 0602 0010 0A00 0000 0004 0000 0100 0000
              000BF120 0000 0001 FF77 0000 0000 0000 0000 0000
              000BF130 0000 0000 0F01 01E5 0000 0000 0000 0204
              000BF140 2014 0000 0200 0032 0032 8889 8888 0000

ARE YOU SURE, (Y/N)  ?

So I set up the keystrokes to start loadinf RAM at $00BF110.

Anyway, I'll report back with some notes on progress (assuming there is some!).
« Last Edit: May 24, 2024, 08:15:04 pm by LittleFrog »
Dave
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #14 on: May 28, 2024, 10:05:00 am »
Hi

There has been progress so here's an update...  I've really written all this down to arrange my own thinking, but if you have any ideas, I'd be most grateful to hear from you.

Review of the set up

My host processor is an MVME110 (i.e. 68000) with 32K bytes of static RAM on board.  The board is running MVME-Bug 4.1 which contains an early version of three commands that let you interact with the HD controller (IOT, IOP & IOC) as well as a number of boot commands which I've not tried because I don't have an image to load.

Then I have two MVME211 static RAM boards, each with 512K bytes of static RAM on board.  I think these work reliably now as I can do block test like this without error;
Code: [Select]
bt 40000 13fffe

I've got a MVME320-1 Disk Controller and I'm trying to use it with a single Hard Disk.  The HD is actually an MFM HD Emulator and although there's no documentation on the file format of the image it stores within itself, I can SSH onto it and see/guess what's going on in real-time which is quite exciting. Documentation for the HD Controller is here;

http://www.bitsavers.org/pdf/motorola/VME/MVME320/MVME320B_D1_Disk_Controller_Users_Manual_Jan88.pdf

And for the emulator here;

https://www.pdp8online.com/mfm/mfm.shtml

Progress

I re-read the HD Controller manual (!) and found that I'd misunderstood the HD connection details.  Cutting a long story short, I'm using a 34 way ribbon cable to connect between the MVME320-1 and the HD Emulator.  I am connecting this to the first 34 pins of J3 (not J4!).  This is achieved using a 50 way IDC header on the end of the 34 way cable.

With this set up in play, and with some working off-board RAM, all three IO commands now do something (rather than hang/timeout).

I can set up the drive dimensions using IOT and then either attempt to issue an IOC or IOP command.

There is a command that does not require any data I/O and this works without error; it's called "Recalibrate to track 0".  I can see the emulator receiving pulses to step off TK0 and then back onto TK0 which is very exciting.  Constructing this command in the ECA and then issuing  an "IOC" is quite fiddly and I use that keystroke generator I described previously.

I can issue an IOP to read HD sectors into RAM but this fails (reason below).  The exciting thing is that if I ask for a block which I know (because of the disk geometry) is on cylinder 32, then I can see the head stepping out to cylinder 32.

Any command that requires data flow always fails with a major status of $01 = "Non-recoverable error" and a minor bit map error of $0008 = "No identifier found".  I guess this is due to the HD not being low-level formatted.

As I said, I've not been able to find documentation on the file format used by the emulator, but it's visible as a disk file and I can SCP it to another computer in "real-time".  The file format seems to be that there's a 102 byte header containing a mix of binary and ASCII.  Then there's basically EVERYTHING that a real HD would read/write on a track by track basis....  So you've got TK0 H0 -> TK0 H1 -> TK0 H2 and so on in a linear, fixed length block.  Each block is separated from the next with a header that I guess is used internally.  Then you can see that the emulator has initialised the fill bytes to some value ($AA).

Getting to the point, I'm not going to get anywhere until I can low-level format the emulator.  I think there are two ways of doing this; issue IOC command type $7 "Format with implied seek" or figure out the format of the emulator file and make one programmatically using some python or similar.  I can't do the second method yet because I don't know how to build an image of a track.

So right now, I'm trying to make the format command work.  This requires constructing an ECA in memory at the correct place expected by the IOC command and then issuing the actual IOC command.

Using "sensible" defaults, I can format part of TK0 and I can see the bytes laid out in the emulator image of the contents of the HD in a sort-of sensible way.
 I'm confident that the whole track is being written which is very exciting.
There are some troubles however;
  • I always get 512 byte sectors even though I think I've set up for 256 byte sectors
  • I only get 3 sectors.  The rest of the track is filled with fill bytes ($A924)
So to me, I'm not constructing the ECA correctly.  Although I mentioned the ECA, the format command also requires a kind of "format map" which tells the controller what order to lay down the sectors and actually what track to lay them out on.  This is how the controller implements interleaving.

So there are three issues at play;
1- Am I constructing the ECA correctly?
2- Am I constructing the format map correctly?
3- Am I pointing the ECA at the format map correctly?

To me, I've got issue one and two sorted.  I'm suspicious that I don't know how to point the ECA at the format map.  The manual is really vague on this which is very frustrating.

What I'm going to do next is gain confidence in my understanding of the ECA by fiddling with the byte level format parameters (e.g. Sync field, Post-ID gap etc...) and then look at the image produced and make sure it's correct.  These are described on pg.8-2 if you're interested.  You put them in the ECA as described on pg. 5-1.

The the format map is so simple, I can't see how I can have it wrong.  It's described on pg. 6-4.

So the final thing is am I pointing the ECA at the format map correctly????  I'm loading the map into memory locations usually used as the data I/O buffer in the ECA; the start and end are seen as "Buffer address" and "Buffer length" but I might have this totally wrong.

Like I said, any comments/thoughts most welcome.

In case you're interested, I've attached a screenshot of part of the emulator disk file; I took this after issuing a format command.  I think you can see the track/sector header and then the actual contents of the freshly low level formatted sector.
« Last Edit: May 28, 2024, 10:13:40 am by LittleFrog »
Dave
 

Online marcopolo

  • Regular Contributor
  • *
  • Posts: 164
  • Country: fr
  • F4LIG
    • Retronik
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #15 on: May 28, 2024, 06:38:50 pm »
Hello Dave,

I think it would be simpler to run a versaDOS installation which will take care of formatting the disk, this is possible with a GOTEK.

Kind Regards,
Marc
My Archives (68K, Old logic, SSB radio): marc.retronik.fr
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #16 on: May 28, 2024, 06:52:47 pm »
Hi,

Thanks for the pointer.  I've searched for versaDOS emulators/installers but found nothing (maybe that was a tip from you in the past actually).  If you could point me at something to get me started, I'd be grateful.

I think you might have proposed two ways forward...  Run some kind of versaDOS emulator (on a Linux box?) or run versaDOS on my 68K hardware with a Gotek emulating a floppy disk.  Have I got that right?

I tried to follow up the versaDOS emulator and found WJM had produced something, for example;

https://groups.google.com/g/comp.sys.m68k/c/kNo3Vz5MM1s

But further googling produced a dead end....  I can't read Usenet posts, or rather I don't know how to read Usenet posts, for free anyway.  So that link above to an old google mirror is all I have.

Further to my recent post, I realise that I might be totally wasting my time trying to create an image of the HD to drop into the emulator because what I'm looking at in the hex dump might be an MFM bit stream; not a conventional byte stream.  Anyway I'm following that up now.

Thanks again for the tip.

PS:  Way off topic but we are planning a trip to your country, I think Mrs Waine has in mind to go to the Loire Valley and then to the Champagne region.  I think you're way over to the east?  Anyway we're looking forward to it.  Tunnel and driving.
Dave
 

Online marcopolo

  • Regular Contributor
  • *
  • Posts: 164
  • Country: fr
  • F4LIG
    • Retronik
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #17 on: May 28, 2024, 07:39:56 pm »
Hi,

The usenet message you quote clearly says (if you read it with a good newsreader):
it is availible through gaby.de... find it in the emulator section..or just google vme10 emulator....the current release is very stable but is still beta... i will be releasing a newer version in a few days, also still beta... i am running a sysgen on it right now..

MOTOROLA VME10 Emulator from Wiley (WJM) : http://www.z80.info/z80emu.htm#EMU_MISC
Disk images: http://www.gaby.de/edownl.htm
I haven't heard from Wiley since December 2023.

Usenet free provider: https://usenet.blueworldhosting.com/

"I realise that I might be totally wasting my time trying to create an image of the HD to drop into the emulator"
Yes, I agree

I can provide you with the images for the GOTEK and the configuration file (created by a friend of mine).

About France, yes I'm in the north-east.


My Archives (68K, Old logic, SSB radio): marc.retronik.fr
 

Offline LittleFrogTopic starter

  • Contributor
  • Posts: 26
  • Country: gb
  • G8SLX
Re: Getting an MVME320B (Motorola VME HD controller) working
« Reply #18 on: May 28, 2024, 08:21:55 pm »
Hi Marco,

This is going to take some reading.  Thanks for the links/tips.

Will be in touch when I've got somewhere with this new direction.
Dave
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf