Ive split the thread. Here is the tool. It wont be much use as it stands because its AVT only, as thats the tool I was developing against before pcmhammer. It would be hard to add support for other interfaces and is probably easier to re-use the kernel with a new UI. I have the source (of course) but its a mess. Most interesting is probably the kernel. Feel free to pull the kernel out of this and re-use it. It shouldnt be too hard to see how it works. I can answer questions and paste code snippets but it'll be in my spare time so its better if you can figure it out yourself. This tool can damage your PCM, so is intended for use only by developers who accept the risk. Its also designed for the P01, though the peek and poke stuff should work fine on a P59. Its a pitty none of the pcmhammer kernel devs except myself have an AVT interface at this state.
This is the test kernel source. Save as test.asm
this is link.lds (use whatever load address you are planning to use. I was playing in FF9150, but available space starts at FF8000.
Code: Select all
| GM '0411 test kernel code
| 2018 Antus / PCMHacking.net
| ===========================================================================
| Flash stuff
.equ SIM_CSBAR0, 0xFFFA4C
.equ SIM_CSORBT, 0xFFFA4A
.equ SIM_CSOR0, 0xFFA4E
.equ SIGNATURE_COMMAND, 0x9090
.equ READ_ARRAY_COMMAND, 0xFFFF
| J1850 registers
.equ J1850_Config, 0xFFF600
.equ J1850_Command, 0xFFF60C
.equ J1850_TX_FIFO, 0xFFF60D
.equ J1850_Status, 0xFFF60E
.equ J1850_RX_FIFO, 0xFFF60F
| misc
.equ COP1, 0xFFFA27
.equ COP2, 0xFFD006
.equ toolid, 0xF0
start:
bsr.w WasteTime
move.b #3, (J1850_Command).l | Flush frame except for completion code
move.b #0, (J1850_TX_FIFO).l | Initiate transfer
wait01:
bsr.w ResetWatchdog | Branch to Subroutine
bsr.w WasteTime | Rate limit RX loop
move.b (J1850_Status).l, %d0 | Get the VPW status
andi.b #0xE0, %d0 | Mask Receive FIFO Status Field (RFS) register 1110 0000
cmpi.b #0xE0, %d0 | Check for "completion code only, at head of buffer" message 1110 0000
bne.s wait01 | not ready? wait and retry
move.b (J1850_RX_FIFO).l, %d0 | strip off the completion code
bsr.w LongWaitWithWatchdog | Branch to Subroutine
MainLoop:
bsr.w J1850_ReadPacket | Wait for and read next frame
cmpi.b #0x35, (InputMode).l | Is it a mode 0x35 (Tool asking PCM to send data) 24 bit
beq.w processmode35 | Process it
cmpi.b #0x36, (InputMode).l | Is it a mode 0x36 (Tool asking PCM to receive data) 24 bit
beq.w processmode36 | Process it
cmpi.b #0x37, (InputMode).l | Is it a mode 0x37 (Tool asking PCM to send data) 32 bit
beq.w processmode37 | Process it
cmpi.b #0x38, (InputMode).l | Is it a mode 0x38 (Tool asking PCM to receive data) 32 bit
beq.w processmode38 | Process it
cmpi.b #0x39, (InputMode).l | Is it a mode 0x39 (Call NVRAM shutdown for 12225074 or 12202088)
beq.b NVRAMShutdown | Jump to it
cmpi.b #0x40, (InputMode).l | Is it a mode 0x40 Get chip ID (non-standard extension)
beq.w FlashID | Process it
cmpi.b #0x20, (InputMode).l | Is it a mode 0x20? (return to normal comms)
bne.w MainLoop | No more options, next packet
movea.l #VPWMode60Msg, %a0 | Reply to a mode 20 with a mode 60 (+40)
move.l #4, %d0 | Message Length
bsr.w WriteVPW_a0_buffer_d0_length | Send normal comms message
bsr.w Stop | Reboot PCM
| =============== S U B R O U T I N E =======================================
NVRAMShutdown:
jsr 0x0270A6 | FIXME: This suits OSID '5074 but not all
LongWaitWithWatchdog:
move.l #0x2710, %d5 | 10,000 loops
waitloop:
bsr.w ResetWatchdog | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
bsr.w WasteTime | Branch to Subroutine
dbf %d5, waitloop | If False Decrement and Branch
rts | Return from Subroutine
| =============== S U B R O U T I N E =======================================
WasteTime:
nop | No Operation
nop | No Operation
nop | No Operation
nop | No Operation
rts | Return from Subroutine
Stop:
move.b #0x40, (J1850_Command).l
move.b #0, (J1850_TX_FIFO).l | Move Data from Source to Destination
bsr.w LongWaitWithWatchdog | Branch to Subroutine
reset | Reset External Devices
EndlessLoop: | Kills PCM, lets COPs expire
bra.s EndlessLoop
| =============== S U B R O U T I N E =======================================
processmode35: | 24 bit address read
bsr.w ResetWatchdog
move.l #6, %d0 | load the mode 35 reply length to d0
movea.l #VPWMode35Reply, %a0 | load the mode 35 reply address to a0
bsr.w WriteVPW_a0_buffer_d0_length | send the static part of the reply
clr.l %d0 | clear d0
or.b (InputAddress1).l, %d0 | the first byte address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress2).l, %d0 | Second address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress3).l, %d0 | third address byte
movea.l %d0, %a0 | move the address to register a0
clr.l %d0 | clear d0
or.b (InputLength1).l, %d0 | 1st length byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputLength2).l, %d0 | second length byte
bsr.w DoReadBlockTransfer_A0_Address_D0_Length | send the actual data
bra.w MainLoop | back to main
| =============== S U B R O U T I N E =======================================
processmode36: | 24 bit address write
bsr.w ResetWatchdog
clr.l %d0 | clear D0
or.b (InputAddress1).l, %d0 | the first byte address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress2).l, %d0 | Second address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress3).l, %d0 | third address byte
movea.l %d0, %a1 | move the dest address to A1
clr.l %d0 | clear D0
or.b (InputLength1).l, %d0 | 1st length byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputLength2).l, %d0 | second length byte
movea.l #Buffer, %a0 | move the data buffer address to A0
move.l (%a0),(%a1) | move the word at the buffer head to the supplied address
move.l #6, %d0 | load the mode 36 reply length to D0
movea.l #VPWMode36Reply, %a0 | load the mode 36 reply address to A0
bsr.w WriteVPW_a0_buffer_d0_length | send the static part of the reply
bra.w MainLoop | back to main
| =============== S U B R O U T I N E =======================================
processmode37: | unofficial 32 bit address read (peek)
bsr.w ResetWatchdog
move.l #6, %d0 | load the mode 35 reply length to d0
movea.l #VPWMode35Reply, %a0 | load the mode 35 reply address to a0
bsr.w WriteVPW_a0_buffer_d0_length | send the static part of the reply
clr.l %d0 | clear d0
or.b (InputAddress1).l, %d0 | the first byte address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress2).l, %d0 | Second address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress3).l, %d0 | third address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (Buffer).l, %d0 | fourth address byte
movea.l %d0, %a0 | move the address to register a0
clr.l %d0 | clear d0
or.b (InputLength1).l, %d0 | 1st length byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputLength2).l, %d0 | second length byte
bsr.w DoReadBlockTransfer_A0_Address_D0_Length | send the actual data
bra.w MainLoop | back to main
| =============== S U B R O U T I N E =======================================
processmode38: | 16 bit address write (poke)
bsr.w ResetWatchdog
clr.l %d0 | clear D0
or.b (InputAddress1).l, %d0 | the first byte address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress2).l, %d0 | Second address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (InputAddress3).l, %d0 | third address byte
lsl.l #8, %d0 | Logical Shift Left
or.b (Buffer).l, %d0 | fourth address byte
movea.l %d0, %a1 | move the dest address to A1
subq.l #1, %a0 | push the buffer along 1 over the extra address byte
movea.l #Buffer, %a0 | move the data buffer address to A0
addq.l #1, %a0 | push the buffer along 1 over the extra address byte
pokenextbyte:
move.w (%a0)+,(%a1)+ | move the byte at buffer head to the supplied address, increment both pointers
move.l #6, %d0 | load the mode 36 reply length to D0
movea.l #VPWMode36Reply, %a0 | load the mode 36 reply address to A0
bsr.w WriteVPW_a0_buffer_d0_length| send the static part of the reply
bra.w MainLoop | back to main
| =============== S U B R O U T I N E =======================================
FlashID:
bsr.w ResetWatchdog
move.w #0x0006, (SIM_CSBAR0).w | default, 0006 set CS registers
move.w #0x6820, (SIM_CSORBT).w | default, 6820
move.w #0x7060, (SIM_CSOR0).w | default 1060, set to 7060
movea.w #0, %a2 | prepare to set address pins to base address
move.w #SIGNATURE_COMMAND, (%a2) | load the signature command to the address pins
move.w (%a2), %d4 | read manufacturer word to d4
movea.w #2, %a2 | Move Address
move.w (%a2), %d3 | Move flash type to d3
movea.w #0, %a2 | Move Address
move.w #READ_ARRAY_COMMAND, (%a2) | Move Data from Source to Destination
move.w %d4, (FlashIDManu).l
move.w %d3, (FlashIDDev).l
movea.l #FlashIDReply, %a0
move #7, %d0
bsr.w WriteVPW_a0_buffer_d0_length| send the static part of the reply
bra.w MainLoop
| =============== S U B R O U T I N E =======================================
WriteVPW_a0_buffer_d0_length:
bsr.w ResetWatchdog | reset watchdog
move.b #0x14, (J1850_Command).l | BTAD Byte type and destination field to 101 (000 101 00)
| 101 = Load as first byte of transmit data
nextbyte:
move.b (%a0)+, (J1850_TX_FIFO).l | Write a byte to to the TX FIFO
bsr.w WasteTime
dbf %d0, nextbyte | If False Decrement and Branch
move.b #0xC, (J1850_Command).l | 011 to BTAD - Load as laste byte of transmit data
move.b (%a0)+, (J1850_TX_FIFO).l | drop the last byte in the TX FIFO
bsr.w WasteTime
move.b #3, (J1850_Command).l | flush buffer
move.b #0, (J1850_TX_FIFO).l | needed for flush buffer?
waitforflush:
bsr.w ResetWatchdog
bsr.w WasteTime
move.b (J1850_Status).l, %d0 | get status byte
andi.b #0xE0, %d0 | check the RFS
cmpi.b #0xE0, %d0 | empty except for completion byte status
bne.s waitforflush | wait until it is true
move.b (J1850_RX_FIFO).l, %d0 | Read FIFO
rts
| =============== S U B R O U T I N E =======================================
DoReadBlockTransfer_A0_Address_D0_Length:
bsr.w ResetWatchdog
move.l %a0, %d1 | copy the address ready to go to d1
move.b %d1, (Mode36Address3).l | move 8 bits of it to the outbound buffer
lsr.l #8, %d1 | Logical Shift Right
move.b %d1, (Mode36Address2).l | move 8 bits of it to the outbound buffer
lsr.l #8, %d1 | Logical Shift Right
move.b %d1, (Mode36Address1).l | move 8 bits of it to the outbound buffer
move.l %d0, %d1 | move the length in d0 to d1
move.b %d1, (Mode36Length2).l | copy 8 bits of length to the outbound buffer
lsr.l #8, %d1 | Logical Shift Right
move.b %d1, (Mode36Length1).l | copy 8 bits of length to the outbound buffer
moveq #9, %d1 | write a 9 to d1 - send 10 bytes?
movea.l #Mode36Header, %a1 | Move Address
move.b #0x14, (J1850_Command).l | 0x14 to BTAD = Load as first byte of transmit data
SendMode36Header:
bsr.w ResetWatchdog
move.b (%a1)+, (J1850_TX_FIFO).l | Move Data from Source to Destination
dbf %d1, SendMode36Header | queue up the reply header
bsr.w ResetWatchdog
subq.l #1, %d0 | decrease length by 1
clr.l %d1 | clear d1
clr.l %d2 | clear d2
move.b (Mode36SubMode).l, %d2 | move a 1 to d2
add.l %d2, %d1 | Add
move.b (Mode36Length1).l, %d2 | start at 1 and add the length and address to get the stop address
add.l %d2, %d1 | Add
move.b (Mode36Length2).l, %d2 | Move Data from Source to Destination
add.l %d2, %d1 | Add
move.b (Mode36Address1).l, %d2 | Move Data from Source to Destination
add.l %d2, %d1 | Add
move.b (Mode36Address2).l, %d2 | Move Data from Source to Destination
add.l %d2, %d1 | Add
move.b (Mode36Address3).l, %d2 | Move Data from Source to Destination
add.l %d2, %d1 | d1 now contains the last byte address
| or d1 contains a sum of the packet so far
trynextbyte:
bsr.w ResetWatchdog
move.b (J1850_Status).l, %d2 | copy the status to d2
andi.b #3, %d2 | mask the TMFS (Transmit FIFO Status) bits
cmpi.b #3, %d2 | 3 = buffer full
beq.s trynextbyte | wait for the TX buffer to be non-full
move.b #4, (J1850_Command).l | 'Load as transmit data' to BTAD
move.b (%a0), (J1850_TX_FIFO).l | copy a byte on to the TX FIFO
move.b (%a0)+, %d2 | Copy the same byte to d2, and increment pointer in a0
add.l %d2, %d1 | maintain a sum in d1
dbf %d0, trynextbyte | repeat if more bytes remaining
move.l %d1, %d0 | copy the sum to d0
lsr.l #8, %d0 | shift the sum right by 8 bits
waitforbuffer:
bsr.w ResetWatchdog
move.b (J1850_Status).l, %d2 | get the status byte in d2
andi.b #3, %d2 | mask TMFS Transmit FIFO Status
cmpi.b #3, %d2 | 3 = Buffer full
beq.s waitforbuffer | wait for room in the TX FIFO
move.b #4, (J1850_Command).l | Load as transmit data
move.b %d0, (J1850_TX_FIFO).l | put the sum in the TX FIFO
waitforbuffer2:
bsr.w ResetWatchdog | Branch to Subroutine
move.b (J1850_Status).l, %d2 | Status byte to d2
andi.b #3, %d2 | Mask TMFS
cmpi.b #3, %d2 | 3=Buffer full
beq.s waitforbuffer2 | Wait for TX buffer to have room
move.b #0xC, (J1850_Command).l | BTAD = "Send IFR on EOD with CRC"
move.b %d1, (J1850_TX_FIFO).l | Move Data from Source to Destination
rts | Return from Subroutine
| =============== S U B R O U T I N E =======================================
J1850_ReadPacket:
clr.l %d6 | reset loop counter
nextframe2:
bsr.w ResetWatchdog
move.b (J1850_Status).l, %d0 | get status byte
andi.b #0xE0, %d0 | Mask The RFS register
cmpi.b #0x40, %d0 | '@' | 010 00000 = Buffer containts a completion code
beq.w framebuffered | jump when we have a frame
addq.l #1, %d6 | increment loop counter
cmpi.l #0x300000, %d6 | have we done 0x300000 loops?
|beq.w Stop | Somethings wrong, let the watchdog reboot it.
bsr.w LongWaitWithWatchdog | Lets see if not hammering the J1850 interface makes it stable:w
bra.s nextframe2 | next try
framebuffered:
movea.l #InputBuffer, %a0 | move the input buffer address to a0
clr.l %d6 | reset loop counter
nextframebyte:
move.b (J1850_RX_FIFO).l, (%a0)+ | read from the RX FIFO to the input buffer, and move the pointer to the next byte
bsr.w ResetWatchdog
move.b (J1850_Status).l, %d0 | get the status byte
andi.b #0xE0, %d0 | Mask RFS register
cmpi.b #0x40, %d0 | '@' | does the buffer contain a completion code? 010 00000
bne.w readcompletioncode | no, packet is complete
addq.l #1, %d6 | increment loop counter
cmpi.l #0x300000, %d6 | have we read 0x300000 bytes yet?
beq.w Stop | kill pcm, let watchdog reboot
bra.s nextframebyte | next try
readcompletioncode:
bsr.w ResetWatchdog
move.b (J1850_RX_FIFO).l, (%a0)+ | this is the completion code, eat it.
movea.l #InputBuffer, %a0 | point a0 to the head of the input buffer
move.b (%a0), %d0
andi.b #0xFE, %d0 | mask 1111 1110
cmpi.b #0x6C, %d0 | is it a priority 6C or 6D packet?
bne.s nextframe2 | if it is not, abort and get the next packet
cmpi.b #0x10, 1(%a0) | Check for device 0x10
beq.w ret | if yes, then return for processing
cmpi.b #0xFE, 1(%a0) | Check for broadcast device id 0xFE
bne nextframe2 | not an FE, junk it and get the next packet
ret:
rts | must have been an FE, return for processing
| =============== S U B R O U T I N E =======================================
ResetWatchdog:
move.b #0x55, (COP1).l | Reset COP1
move.b #0xAA, (COP1).l
bclr #7, (COP2).l | Reset COP2
bset #7, (COP2).l
rts
| ---------------------------------------------------------------------------
.byte 0x0D
.ascii "(c)2018 antus@pcmhacking.net"
InputBuffer: .byte 0x01, 0x00, 0x00
InputMode: .byte 0x00, 0x00
InputLength1: .byte 0x00
InputLength2: .byte 0x00
InputAddress1: .byte 0x00
InputAddress2: .byte 0x00
InputAddress3: .byte 0x00
Buffer: .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
VPWMode60Msg: .byte 0x6C, toolid, 0x10, 0x60
VPWMode35Reply: .byte 0x6C, toolid, 0x10, 0x75, 0x01, 0x54
VPWMode36Reply: .byte 0x6C, toolid, 0x10, 0x76, 0x01, 0x54
Mode36Header: .byte 0x6D, toolid, 0x10, 0x36
Mode36SubMode: .byte 0x01
Mode36Length1: .byte 0x00
Mode36Length2: .byte 0x00
Mode36Address1: .byte 0x00
Mode36Address2: .byte 0x00
Mode36Address3: .byte 0x00
FlashIDReply: .byte 0x6C, toolid, 0x10, 0x80, 0x01
FlashIDManu: .byte 0x00, 0x00
FlashIDDev: .byte 0x00, 0x00
.end