Jump to content

Photo

Intellivision Blue/Black Whale Reverse Engineering Report

intellivision reverse engineering black whale blue whale keyboard component

18 replies to this topic

#1 intvnut ONLINE  

intvnut

    River Patroller

  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Mon Apr 23, 2018 11:45 PM

I'm finally getting around to posting the Blue Whale / Black Whale reverse engineering document.
 
The document calls it Black Whale.  But, in talking with Steve Roney and Bill Fisher, nobody there remembers any name other than Blue Whale for this device.  In any case, there's extensive reverse engineering notes including schematics, commented disassembly, a user's guide, and pictures.  All in all, about 100 pages of goodies.
 
There's one little bit of disassembly on the 6502 side I haven't 100% worked out:  The code that stitches the debugger into the KC's menu.  The rest, though, is pretty thoroughly understood.
 
Enjoy!
 
____________

 

Revision History

  • 2018-04-23, A:  Initial public release, immediately withdrawn
  • 2018-04-23, B:  Regenerated to fix some last-minute formatting issues.
  • 2018-04-24, A:  Corrected descriptions of code that rewinds PC when hitting a breakpoint, and the code that interprets SDBD : xxx@ Rx, R7 when single stepping.

Edited by intvnut, Wed Apr 25, 2018 12:49 AM.


#2 decle OFFLINE  

decle

    Chopper Commander

  • 224 posts
  • 0x10 bits or less

Posted Tue Apr 24, 2018 12:21 AM

I highly recommend people have a good read of this, it is an excellent piece of work, well worth the time.  Another bit of the development tools puzzle is documented and understood.

 

I want to say thanks

  • to Joe and Frank for undertaking the analysis
  • to Joe for taking the time to write up the results
  • to Daniel Bass for lending the boards to study
  • to Intellivision Productions for their pragmatic view on allowing this bit of their IP to be shared

I think that, like the TutorVision study, this is an excellent example of how the community can come together to preserve and share information that is of little commercial value, but of technical interest.

 

Great job, now home in time for tea and medals!


Edited by decle, Tue Apr 24, 2018 12:22 AM.


#3 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Tue Apr 24, 2018 11:55 AM

I'm finally getting around to posting the Blue Whale / Black Whale reverse engineering document.
 
The document calls it Black Whale.  But, in talking with Steve Roney and Bill Fisher, nobody there remembers any name other than Blue Whale for this device.  In any case, there's extensive reverse engineering notes including schematics, commented disassembly, a user's guide, and pictures.  All in all, about 100 pages of goodies.
 
There's one little bit of disassembly on the 6502 side I haven't 100% worked out:  The code that stitches the debugger into the KC's menu.  The rest, though, is pretty thoroughly understood.
 
Enjoy!
 
[Edit: I noticed a minor problem with the first version I posted.  Here is the 'B' version.]


Very interesting!!! Great work! :thumbsup:

There is one thing I am not clear on: how did the MOS6502 interrupt the CP1610 and trapped breakpoints?

Your document seems to suggest that it is just polling on the serial connection, but then how does it detect that a particular breakpoint has been reached and needs to interrupt? Is it using the heretofore unhooked software interrupt line of the CP1610? (Perhaps that's what "SIN" means?)

Then again, the document also says that interrupt-driven control was discarded for some reason. I'm a bit confused...

Sorry if this seems like a silly question, but I am not a hardware guy. In the past I had posited in this forum how a hardware debugger might work in theory by hooking to the software interrupt line of the CPU, but that would require a modification to the console. From what I could surmise from your document, this is one of the requirements at the beginning during the setup of the environment, no?

Perhaps I'm completely off the mark, in which case I would appreciate some guidance. :)

dZ.

#4 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Tue Apr 24, 2018 12:11 PM

Very interesting!!! Great work! :thumbsup:

There is one thing I am not clear on: how did the MOS6502 interrupt the CP1610 and trapped breakpoints?

Your document seems to suggest that it is just polling on the serial connection, but then how does it detect that a particular breakpoint has been reached and needs to interrupt? Is it using the heretofore unhooked software interrupt line of the CP1610? (Perhaps that's what "SIN" means?)

Then again, the document also says that interrupt-driven control was discarded for some reason. I'm a bit confused...

Sorry if this seems like a silly question, but I am not a hardware guy. In the past I had posited in this forum how a hardware debugger might work in theory by hooking to the software interrupt line of the CPU, but that would require a modification to the console. From what I could surmise from your document, this is one of the requirements at the beginning during the setup of the environment, no?

Perhaps I'm completely off the mark, in which case I would appreciate some guidance. :)

dZ.

 
The 6502 has two interrupt pins, ~NMI and ~IRQ.  ~NMI is the 6502 non-maskable interrupt, while ~IRQ is the 6502 maskable interrupt.  The serial port can assert ~IRQ to the 6502.  It appears initially the software used that approach to handle serial I/O, but later they disabled interrupts on the 6502 and now the 6502 polls the serial port directly.
 
The CP1610 has two interrupt pins, INTR* and INTRM*.  INTRM* is connected to the STIC vertical retrace signal.  INTRM* is the maskable interrupt pin. INTR* is pulled high by a 5.6KΩ resistor.  INTR* is the non-maskable interrupt pin.  The Black Whale mod requires you to connect INTR* to PCIT* so that the SIN instruction on the CP1610 triggers a non-maskable interrupt on the CP1610.
 
The 6502 cannot trigger an interrupt on the CP1610.
 
The two processors have their own separate interrupts, and they're handled separately.  The 6502 disables interrupts and does everything with polling.  The CP1610 operates under the control of whatever game you've loaded, doing EIS/DIS as normal to mask/unmask vertical retrace interrupts.  The SIN/SIN2 opcodes trigger a non-maskable interrupt on the CP1610 if you wire the PCIT* pin to the INTR* pin.  The breakpoint mechanism in the black whale uses SIN in this manner.

Edited by intvnut, Wed Apr 25, 2018 12:06 AM.


#5 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Tue Apr 24, 2018 12:21 PM

 
The 6502 has two interrupt pins, ~NMI and ~IRQ.  ~NMI is the 6502 non-maskable interrupt, while ~IRQ is the 6502 maskable interrupt.  The serial port can assert ~IRQ to the 6502.  It appears initially the software used that approach to handle serial I/O, but later they disabled interrupts on the 6502 and now the 6502 polls the serial port directly.
 
The CP1610 has two interrupt pins, *INTR and *INTRM.  *INTRM is connected to the STIC vertical retrace signal.  *INTRM is the maskable interrupt pin.    *INTR is pulled high by a 5.6KΩ resistor.  *INTR is the non-maskable interrupt pin.  The Black Whale mod requires you to connect *INTR to *PCIT so that the SIN instruction on the CP1610 triggers a non-maskable interrupt on the CP1610.
 
The 6502 cannot trigger an interrupt on the CP1610.
 
The two processors have their own separate interrupts, and they're handled separately.  The 6502 disables interrupts and does everything with polling.  The CP1610 operates under the control of whatever game you've loaded, doing EIS/DIS as normal to mask/unmask vertical retrace interrupts.  The SIN/SIN2 opcodes trigger a non-maskable interrupt on the CP1610 if you wire the *PCIT pin to the *INTR pin.  The breakpoint mechanism in the black whale uses SIN in this manner.


Great! Thanks for the response and for clearing it up, it's as I thought (although I had confused some of the pieces, and had some of the terminology wrong). I think I'm clear now.

So, my follow question is: what triggers the SIN on the CP1610? I saw that the code compares the interrupted address against the breakpoint list, but what causes it to interrupt?


UPDATE: if I understand correctly, it's the running program that issues the SIN, right? If so, the program would need to be modified to include these periodically, correct?

#6 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Tue Apr 24, 2018 12:24 PM

So, my follow question is: what triggers the SIN on the CP1610? I saw that the code compares the interrupted address against the breakpoint list, but what causes it to interrupt?

 
SIN pulses the PCIT* pin, which is why you need to connect PCIT* to INTR* so that SIN results in a non-maskable interrupt.  (SIN2 also.)

Edited by intvnut, Wed Apr 25, 2018 12:07 AM.


#7 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Tue Apr 24, 2018 12:36 PM

 
SIN pulses the *PCIT pin, which is why you need to connect *PCIT to *INTR so that SIN results in a non-maskable interrupt.  (SIN2 also.)


I got that. Perhaps I am not expressing myself adequately, or maybe my question is completely ignorant and has you scratching your head, but what I am trying to understand is where are the SIN instructions located? Are they peppered throughout the game program you are trying to debug?

dZ.

#8 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Tue Apr 24, 2018 12:40 PM

In other news, the Intellivision Wiki states the following about the SIN instruction:

"It is unclear if this instruction has any other behaviour, useful or not."

That is because the PCIT pin was not connected to anything in an Intellivision.

Perhaps if you have a modified Master Component now you can test it thoroughly and expand on it's full specification?

#9 carlsson OFFLINE  

carlsson

    Metagalactic Mule

  • 7,676 posts
  • Location:Västerås, Sweden

Posted Tue Apr 24, 2018 12:42 PM

Regarding your (less important) question at the end of the document whether TV sets in Europe used to have the same two dials: yes, at least for some B&W models. I've got a combo 10" TV, radio, tape recorder that has one dial for VHF channels 5-12 (or perhaps it is VHF 1-12) plus a UHF setting which enables the other dial to tune in UHF 21-69 IIRC. They may not have been entirely common, but appears to have existed.

 

Example image, which I've always assumed to be domestic rather than borrowed from another source:

 

vic20-folkdatorn.jpg



#10 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Tue Apr 24, 2018 12:59 PM

I got that. Perhaps I am not expressing myself adequately, or maybe my question is completely ignorant and has you scratching your head, but what I am trying to understand is where are the SIN instructions located? Are they peppered throughout the game program you are trying to debug?

dZ.

 

Have a look at the CP1610 side of the debugger, starting at page 74.  The commented disassembly goes into extensive detail on how breakpoints are managed (inserting/removing SIN instructions, chasing both sides of conditional branches, when SIN vs. SIN2 gets used, etc).  In particular the routines at $8A4A and $8A65.

 

To quote the old Ragu ad: "It's in there!"



#11 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Tue Apr 24, 2018 1:03 PM

Thank you, I guess I'm too dense to understand it, for I already read the document and posted here. But hey, thanks. *sigh*

dZ.

#12 ianoid OFFLINE  

ianoid

    River Patroller

  • 2,923 posts
  • Location:TEXAS!!!

Posted Tue Apr 24, 2018 1:55 PM

Will this document help to design an emulator for the Whale Keyboard Component? That's about the only way most people will get to enjoy the system. 



#13 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Tue Apr 24, 2018 2:23 PM

Thank you, I guess I'm too dense to understand it, for I already read the document and posted here. But hey, thanks. *sigh*

 

I apologize for the terse responses.  I'm at $DAYJOB replying between meetings.

 

The function at $8A4A (page 85) steps through the breakpoint address list, copying instruction out of the program at the breakpoint addresses to a separate buffer, and replacing them with SIN instructions.  This gets called just before running the program.  There's a converse function at $8D07 (page 97) that replaces the SIN,1 instructions with the original instructions.  Those two functions are fairly simple, and give you basic breakpoint capability

 

The function at $8A65 (pages 85 - 92 (!!)) is for single stepping.  It actually tries to decode the length of an instruction, even accounting for conditional branches (finding both legs of the conditional branch), JSRs with data after them (at least for commonly-used EXEC subroutines), and so forth.  For instructions that modify R7, it actually modifies the opcode to see what effect the instruction has on R7, so it can single-step over jump tables.  It's crazy.  The single-step code uses SIN,2 (opcode $37) rather than SIN,1 (opcode $36).  The two opcodes both behave the same in the CPU; the different opcodes are there for software to distinguish a breakpoint from a single-step in the interrupt handler.  The function at $8D1F (page 97) replaces the SIN,2 instructions with the original instructions.

 

The INTR handler at $8C2B (pages 93-95) decodes whether we hit a breakpoint (SIN,1), the far side of a single-step (SIN,2), or an ordinary interrupt.

 

BTW, while writing this post, I noticed an error in the doc, which I went and fixed in the original Google Doc.  This bit is wrong:

.

L_8C62: MVO@    R2,     R3          ; 8C62  This looks like dead code. 
                                    ;       We read R2 from @R3 above, and 
                                    ;       now we write it unmodified to @R3

.

Actually, R2 is modified.  It's decremented by 1 at $8C3A.  So, I've corrected that to read:

.

L_8C62: MVO@    R2,     R3          ; 8C62  Rewrite the program counter on the
                                    ;       stack to point to the instruction
                                    ;       we had replaced with SIN,1. 

.

 

I'm sure I've made a few other minor flubs here and there.  I'm rather embarrassed by that one though.  It seems rather obvious in retrospect that if we take an interrupt due to SIN, the saved program counter will point after SIN.  To resume at the breakpoint, you need to rewind the PC to point to the SIN instruction and replace it with the original instruction.


Edited by intvnut, Tue Apr 24, 2018 2:24 PM.


#14 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Tue Apr 24, 2018 2:36 PM

In other news, the Intellivision Wiki states the following about the SIN instruction:

"It is unclear if this instruction has any other behaviour, useful or not."

That is because the PCIT pin was not connected to anything in an Intellivision.

Perhaps if you have a modified Master Component now you can test it thoroughly and expand on it's full specification?

 

As best as I can tell, SIN is fully described in this document: http://spatula-city....anual_May75.pdf

 

Flip to pages 13 (description of PCIT* pin), and page 34 (PCIT* Timing).

 

All it really does is pulse the PCIT* pin.  That's it.  It pulses it in a way that's suitable for tying back to INTR* or INTRM*.



#15 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Tue Apr 24, 2018 2:37 PM

Will this document help to design an emulator for the Whale Keyboard Component? That's about the only way most people will get to enjoy the system. 

 

Not really. Frank and I have been chipping away at it (Frank more than I) for awhile.  There's a KC emulator in MAME now that Frank wrote.  It doesn't have tape drive support yet, but it will eventually.



#16 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Tue Apr 24, 2018 3:30 PM

 
I apologize for the terse responses.  I'm at $DAYJOB replying between meetings.
 
The function at $8A4A (page 85) steps through the breakpoint address list, copying instruction out of the program at the breakpoint addresses to a separate buffer, and replacing them with SIN instructions.  This gets called just before running the program.  There's a converse function at $8D07 (page 97) that replaces the SIN,1 instructions with the original instructions.  Those two functions are fairly simple, and give you basic breakpoint capability
 
The function at $8A65 (pages 85 - 92 (!!)) is for single stepping.  It actually tries to decode the length of an instruction, even accounting for conditional branches (finding both legs of the conditional branch), JSRs with data after them (at least for commonly-used EXEC subroutines), and so forth.  For instructions that modify R7, it actually modifies the opcode to see what effect the instruction has on R7, so it can single-step over jump tables.  It's crazy.  The single-step code uses SIN,2 (opcode $37) rather than SIN,1 (opcode $36).  The two opcodes both behave the same in the CPU; the different opcodes are there for software to distinguish a breakpoint from a single-step in the interrupt handler.  The function at $8D1F (page 97) replaces the SIN,2 instructions with the original instructions.
 
The INTR handler at $8C2B (pages 93-95) decodes whether we hit a breakpoint (SIN,1), the far side of a single-step (SIN,2), or an ordinary interrupt.
 
BTW, while writing this post, I noticed an error in the doc, which I went and fixed in the original Google Doc.  This bit is wrong:
.

L_8C62: MVO@    R2,     R3          ; 8C62  This looks like dead code. 
                                    ;       We read R2 from @R3 above, and 
                                    ;       now we write it unmodified to @R3
.
Actually, R2 is modified.  It's decremented by 1 at $8C3A.  So, I've corrected that to read:
.
L_8C62: MVO@    R2,     R3          ; 8C62  Rewrite the program counter on the
                                    ;       stack to point to the instruction
                                    ;       we had replaced with SIN,1. 
.
 
I'm sure I've made a few other minor flubs here and there.  I'm rather embarrassed by that one though.  It seems rather obvious in retrospect that if we take an interrupt due to SIN, the saved program counter will point after SIN.  To resume at the breakpoint, you need to rewind the PC to point to the SIN instruction and replace it with the original instruction.

No worries. I appreciate the additional information. It turns out that the part I completely missed (or misunderstood) was this:

"The function at $8A4A (page 85) steps through the breakpoint address list, copying instruction out of the program at the breakpoint addresses to a separate buffer, and replacing them with SIN instructions"

That is quite clever! :)

The single-stepping feature I had understood from your document and impressed me quite a lot! It's very interesting that they are actually simulating each op-code, that's wild!

dZ.

#17 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Tue Apr 24, 2018 7:54 PM

Will this document help to design an emulator for the Whale Keyboard Component? That's about the only way most people will get to enjoy the system. 

 

I should shade my previous response:  Frank did do some additional circuit tracing work and so forth that has increased our understanding about how the KC operates, and that was inspired by this effort.

 

The Blue(Black?) Whale hardware itself hasn't taught us much more about the KC, but it forced us to learn more about the KC to understand it.  Does that make sense?

 

For example, we discovered there's a -5V line that comes to the KC expansion port, and it's a low-current line.  You don't want to draw much current from it.  We sussed that out from looking at the RS232 line drivers and wondering "Is there a negative voltage on this line?"  Frank traced it out....

 

We also determined that ø2 is 895kHz, just like the MC's instruction clock.  We needed to know that to determine the BW's baud rate.  Frank put the clock signal on a scope and now we know. 

 

We also validated that the KC's 6502 EXEC at $C000 - $DFFF seems to get mirrored at $E000 - $FFFF, unless an expansion cartridge claims the address range.  Frank traced out those circuits to verify that while I was off reverse engineering the code.

 

Those were all details we could have worked out w/out the BW boards.  But with the BW boards in hand, we had more motivation to find those details out sooner rather than later.



#18 Lathe26 ONLINE  

Lathe26

    River Patroller

  • 3,652 posts

Posted Tue Apr 24, 2018 9:32 PM

Awesome, thanks for sharing!



#19 intvnut ONLINE  

intvnut

    River Patroller

  • Topic Starter
  • 3,082 posts
  • Location:@R6 (top of stack)

Posted Wed Apr 25, 2018 12:55 AM

In the interests of accuracy and transparency:  I've updated post #1 with a new version.  There are two minor changes.  First is the error I mentioned in post #13 above.

 

The second involves this little bit of code in the single-step routine:

.

        CMPI    #$0001, R1          ; 8B08  \_ I think this is always taken?
        BNEQ    L_8B2E              ; 8B0A  /

        ;; ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ ;;
        ;;  Not sure the following is reachable. It attempts to execute     ;;
        ;;  an instruction to see what it might do to the target register.  ;;
        ;; ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ ;;

.

It turns out that that code should be reachable if you have SDBD ; xxx@ Rx, R7.  So now this snippet reads:

.

        CMPI    #$0001, R1          ; 8B08  \_ Did we arrive here due to SDBD?
        BNEQ    L_8B2E              ; 8B0A  /  (See code at $8BAD.)

        ;; ---------------------------------------------------------------- ;;
        ;;  Based on the code at $8BAD, we arrive here if SDBD modifies an  ;;
        ;;  instruction that isn’t an immediate-mode instruction, but does  ;;
        ;;  modify R7 (given the comparison at $8AF0).                      ;;
        ;; ---------------------------------------------------------------- ;;

.

Other than that, there are no material changes.  I did add a Revision History page at the end to track future changes to the document.


Edited by intvnut, Wed Apr 25, 2018 1:00 AM.






Also tagged with one or more of these keywords: intellivision, reverse engineering, black whale, blue whale, keyboard component

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users