------------------------------------------------------------------
Our first page on IRIS Disassembly can be found here.
Please consider this page an additional chapter into the disassembly and deeper study of the Point 4 IRIS assembly language, and various example programs.
To start with, Tom has documented well a high-level of the assembly language of this system, in his web page:
The Data General Nova
------------------------------------------------------------------
The files which are the focus of this disassembly project are from the Microtech Dart Utility, bootable tape. Details and all source files can be downloaded from here:
Microtech Dart Utility Tape
-------------------------------------------------------------------
A breakthrough !! At last something that looks like real code!!!!
The following is from my disassembly of file01 (the alleged boot loader). Just for the record, I was suspicious this
was a boot loader all along. I mean, what else would you put as the first record of a tape, and what else would
be only 512 bytes.
0050: 31f0 030760 1p lda r2,0040 ; 000100, pc-10
0051: 39f0 034760 9p lda r3,0041 ; 000101, pc-10
0052: 2200 021000 " lda r0,r2+00
0053: 4300 041400 C sta r0,r3+00
0054: d300 151400 S inc r2,r2
0055: fb00 175400 { inc r3,r3
0056: 19ec 014754 l dsz 0042 ; 000102, pc-14
0057: 01fb 000773 { jmp 0052 ; 000122, pc-05
Two things led to this breakthrough. One was fixing an address display bug in my disassembler, the other
was using the byte order as you originally sent me. I was trying both endiannesses but was biased towards
swapping what you had sent based on file 14 or 15 showing text properly when I swapped it, but clearly you
had the byte order right for this file (but we know there are some exceptions later).
And a note for Alan -- I have deviated from the usual Nova assembler syntax. I display values as
hex (not octal) and indicate registers as r0, .... not just a number or ac3.
The first 4 columns above are:
-- address in hex
-- contents in hex
-- contents in octal
-- contents as ascii (with high bit cleared)
Anyway, here is a play by play on the above:
1) load register r2 from address 0x0040 (this loads zero)
2) load register r3 from address 0x0041 (this loads 0x6d00)
now a loop begins
3) load register r0 from the address pointed to by r2
4) store register r0 to the address pointed to by r3
5,6) increment r2 and r3
7) decrement and skip if zero on location 42.
This initially has the value 0x100 (a count of 256)
8) jump to keep the loop going.
So what is this doing? It is a block copy of 256 words (512 bytes) starting from address 0000
and depositing it at address 0x6d00.
So -- this is where I had hoped to get all day yesterday; a piece of assembly language that I could comment on
an explain to get your "pump primed".
I am so happy.
And you need to comment on how you like the format. Changes are easy to make.
I have contemplated putting 0x in front of all hex, but think it will just make a mess.
Also some way to indicate octal (I am tempted to use a leading % sign).
Note that for a pc relative address, I calculate the actual address and display it (as in jmp 0052).
I could care less if it was encoded as a PC relative value, I want to look at the code and know where
I am jumping. In the comment I put the octal value and the pc-05 thing for the curious, though I
don't really know what purpose that might serve.
-------------------------------------------------------------
Here is the entire disassembly of the 256 word boot loader (file01), which sort of showcases
the current disassembler output. The disassembler itself is only 179 lines of ruby. I will send
it along as well once I think it is semi-stable. I am waiting to see if Alan screams when he sees
the Nova syntax I am generating. I added options to switch off the column of ascii display
as well as the octal, so this output is kinda "lean and mean". I did add the "%" prefix to all
octal values and decided to display the device codes for the IO instructions in octal since
the Nova manual always seems to cite these as octal. You will see the leading "%" for these.
Everything else is hex (we don't want confusion about what base things are displayed in).
------------------------------------------------------------
For anyone who actually used to look at and handle Point-4 computers, here is a question for you:
How do they boot up? I mean if you shove a tape in, how do you make it boot from tape?
What insights do you have about how this 256 word loader would get loaded?
Why does the first bit of real code seem to be at address 0x50, does that ring any
bells with you?
I would expect this thing to get loaded into address zero and the PC get set to 0 to run,
but if execution started at address 0, it would run a bunch of docp instructions, then
at address 0x40 hit a jump back to zero, hence running some endless unwrapped loop
of just docp instructions. It is odd that the value 0x7eff appears like padding at the
start and end of this file or block or record or whatever you want to call it.
The end of the block may have a clue. It ends with an indirect jump through 0x00fe
which would take it to the loop I found at address 0x0050. Is this some defined Nova
behavior? Load a 256 word block and then set the PC to run the instruction in the
last word? In that case, why would it not just be a jump to 0050 itself?
------------------------------------------------------------
Nova boot loader annotation
OK, I studied my disassembly of the Nova bootloader, and as I like to do when studying some
disassembled code, annotated it with comments.
Also found a bug in the disassembler (recently introduced) and added an option to disassemble
at a specified address (as was needed to handle the address relocation).
------------------------------------------------------------
Disassembled [Microtech Dart Utility] file 2 and working on it.
It makes good sense also.
It has text strings. It will be curious to see how they get printed.
Also, I just learned that the order of registers in ALU instructions is not
what I expect (you probably don't have any expectations on this).
So if you have:
add r1, r2
It adds r1+r2 and puts the result in r2 (other assemblers have the destination register first).
Well this order matches the register encoding in the instruction, not that that matters.
Actually as long as we KNOW what is first, we are OK. Likewise
mov r1, r2
moves a value from r1 to r2 (i.e r2=r1 gets done).
Tom
------------------------------------------------------------
#!/bin/ruby
# Nova (Point-4) Disassembler
# Tom Trebisky 5-30-2016
#
# At this time, you must enter the input filename below.
# also note the true/false options to enable extra
# stuff in the output.
# Output to stdout.
#infile = "Files/nova15.bin"
#infile = "Files/nova02.bin"
infile = "Files/nova01.bin"
# 22 has strings indicating it is a Point 4 disk utility
#infile = "Files/nova22.bin"
#infile = "nova22.swab"
$show_octal = false
$show_ascii = false
$show_pcrel = false
$swap_bytes = false
$start_address = 0x6d00
# -----------------------------------------------------
# -----------------------------------------------------
# This yields a big string
buf = IO.binread ( infile )
# This yields an array of 16 bit items
if ( $swap_bytes )
words = buf.unpack('n*')
else
#words = buf.unpack('S*')
words = buf.unpack('v*')
end
$io_ops = %w( nio dia doa dib dob dic doc skp )
$skp_ctrl = %w( bn bz dn dz )
$xfer_ctrl = [ " ", "s", "c", "p" ]
def io_decode ( w )
op = (w >> 8) & 0x7
sop = $io_ops[op]
ctrl = (w >> 6) & 0x3
if ( op == 7 )
sop += $skp_ctrl[ctrl]
else
sop += $xfer_ctrl[ctrl]
end
reg = (w >> 11) & 0x3
sreg = "r#{reg}"
dev = "%" + "%o" % (w & 0x3f)
return sop + "\t\t" + sreg + "," + dev
end
$alu_ops = %w( com neg mov inc adc sub add and )
$carry_l = [ "", "z", "o", "c" ]
$shift_l = [ "", "l", "r", "s" ]
$sk_ops = %w( --- skp szc snc szr snr sez sbn )
def alu_decode ( w )
rs = "r%d" % ((w>>13) & 0x3)
rd = "r%d" % ((w>>11) & 0x3)
op = (w>>8) & 0x7
sop = $alu_ops[op]
carry = (w>>4) & 0x3
sop += $carry_l[carry]
shift = (w>>6) & 0x3
sop += $shift_l[shift]
if ( ( w & 0x8 ) == 0x8 )
sop += "#"
end
sop += " " if ( carry == 0 )
sop += " " if ( shift == 0 )
sk = w & 0x7
if ( sk != 0 )
return sop + "\t\t" + rs + "," + rd + "," + $sk_ops[sk]
else
return sop + "\t\t" + rs + "," + rd
end
end
def to_signed ( uval )
return uval if uval < 128
return uval - 256
end
def to_octal ( val )
return "%" + "%06o" % val
end
def mem_addr ( w )
rv = ""
if ( (w & 0x400) == 0x400 )
rv = "@"
end
udisp = w & 0xff
bdisp = to_signed udisp
# print "#{udisp} #{bdisp}\n"
if ( bdisp < 0 )
disp = "-%02x" % -bdisp
else
disp = "+%02x" % bdisp
end
if ( (w & 0x300) == 0 )
# absolute address.
uaddr = "%04x" % udisp
if ( $show_octal )
return rv + uaddr + "\t\t; " + to_octal( udisp )
else
return rv + uaddr
end
elsif ( w & 0x300 == 0x100 )
# PC relative address
pcaddr = $addr + bdisp
spcaddr = "%04x" % pcaddr
rv += spcaddr
if ( $show_octal )
opcaddr = to_octal pcaddr
rv += "\t\t; " + opcaddr
end
if ( $show_pcrel )
if ( $show_octal )
rv += ", pc" + disp
else
rv += "\t\t; pc" + disp
end
end
return rv
elsif ( w & 0x300 == 0x200 )
return rv + "r2" + disp
else
return rv + "r3" + disp
end
end
def ls_addr ( w )
reg = (w >> 11) & 0x3
return "r#{reg}," + mem_addr( w )
end
$mem_ops = %w( jmp jsr isz dsz lda lda lda lda sta sta sta sta )
def mem_decode ( w )
op = (w>>11) & 0xf
if ( op < 4 )
return $mem_ops[op] + "\t\t" + mem_addr( w )
else
return $mem_ops[op] + "\t\t" + ls_addr( w )
end
end
def decode ( w )
if ( w & 0xe000 == 0x6000 )
return io_decode ( w )
elsif ( w & 0x8000 == 0x8000 )
return alu_decode ( w )
else
return mem_decode ( w )
end
end
def show_ascii ( w )
b1 = (w >> 8) & 0x7f
b2 = w & 0x7f
c1 = b1.chr
c2 = b2.chr
c1 = " " if ( b1 <= 0x20 or b1 >= 0x7f )
c2 = " " if ( b2 <= 0x20 or b2 >= 0x7f )
return c1 + c2
end
$addr = $start_address
words.each { |w|
ad = "%04x" % $addr
ww = "%04x" % w
outline = ad + ":\t" + ww + "\t"
if ( $show_octal )
ow = to_octal w
outline += ow + "/t"
end
if ( $show_ascii )
cc = show_ascii w
outline += cc + "/t"
end
ins = decode w
outline += "\t" + ins + "\n"
print outline
$addr += 1
}
# THE END
------------------------------------------------------------------
No comments:
Post a Comment