src/musashi/example/example.txt

Mon, 14 Jan 2013 09:22:12 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Jan 2013 09:22:12 +0000
changeset 118
feee84e0b3bf
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

More bus error fixes for FreeBee

I have fixed two more bus error handling bugs in FreeBee. First, the CPU core was executing the instruction regardless of whether a bus error occurs when fetching the opcode (which caused it to execute a bogus instruction in such cases). The other one was related to one of my previous fixes - the jump to the bus error vector was at the beginning of the main loop, so it wouldn't be called immediately after the bus error occurred if the timeslot expired, causing the return address to be off.

With these fixes, Unix now runs enough to get into userspace and run the install script (it is also possible to break out and get a shell prompt). However, many commands segfault semi-randomly (or more specifically, it seems that some child processes forked by the shell might be segfaulting before they can exec the command program), so installing the system isn't possible yet. I am not sure exactly what the bug is, but it seems to be related to some function in the shell returning null when the code calling it is assuming that it won't. What the function is, or why it is returning null, I'm not sure (the shell is built without the shared libc and is stripped, making identifying the function harder). I suspect that the function might be in libc, but that is hard to tell.

Author: Andrew Warkentin <andreww591 gmail com>

philpem@0 1 EXAMPLE:
philpem@0 2 -------
philpem@0 3 As an example, I'll build an imaginary hardware platform.
philpem@0 4
philpem@0 5
philpem@0 6 The system is fairly simple, comprising of a 000, an input device, an output
philpem@0 7 device, a non-maskable-interrupt device, and an interrupt controller.
philpem@0 8
philpem@0 9
philpem@0 10 The input device receives input from the user and asserts its interrupt
philpem@0 11 request line until its value is read. Reading from the input device's
philpem@0 12 memory-mapped port will both clear its interrupt request and read an ASCII
philpem@0 13 representation (8 bits) of what the user entered.
philpem@0 14
philpem@0 15 The output device reads value when it is selected through its memory-mapped
philpem@0 16 port and outputs it to a display. The value it reads will be interpreted as
philpem@0 17 an ASCII value and output to the display. The output device is fairly slow
philpem@0 18 (it can only process 1 byte per second), and so it asserts its interrupt
philpem@0 19 request line when it is ready to receive a byte. Writing to the output device
philpem@0 20 sends a byte to it. If the output device is not ready, the write is ignored.
philpem@0 21 Reading from the output device returns 0 and clears its interrupt request line
philpem@0 22 until another byte is written to it and 1 second elapses.
philpem@0 23
philpem@0 24 The non-maskable-interrupt (NMI) device, as can be surmised from the name,
philpem@0 25 generates a non-maskable-interrupt. This is connected to some kind of external
philpem@0 26 switch that the user can push to generate a NMI.
philpem@0 27
philpem@0 28 Since there are 3 devices interrupting the CPU, an interrupt controller is
philpem@0 29 needed. The interrupt controller takes 7 inputs and encodes the highest
philpem@0 30 priority asserted line on the 3 output pins. the input device is wired to IN2
philpem@0 31 and the output device is wired to IN1 on the controller. The NMI device is
philpem@0 32 wired to IN7 and all the other inputs are wired low.
philpem@0 33
philpem@0 34 The bus is also connected to a 1K ROM and a 256 byte RAM.
philpem@0 35 Beware: This platform places ROM and RAM in the same address range and uses
philpem@0 36 the FC pins to select the correct address space!
philpem@0 37 (You didn't expect me to make it easy, did you? =)
philpem@0 38
philpem@0 39 There are two ways to handle address spaces with Musashi:
philpem@0 40
philpem@0 41 1. Enable M68K_SEPARATE_READS and make handler functions for immediate and
philpem@0 42 pc-relative reads.
philpem@0 43
philpem@0 44 2. Enable M68K_EMULATE_FC and make a callback function for function code
philpem@0 45 changes.
philpem@0 46
philpem@0 47 Both methods will work in this case, but I've opted for the "more correct"
philpem@0 48 function code pin emulation for this example.
philpem@0 49
philpem@0 50
philpem@0 51
philpem@0 52 Here is the schematic in all its ASCII splendour:
philpem@0 53 -------------------------------------------------
philpem@0 54
philpem@0 55 NMI TIED
philpem@0 56 SWITCH LOW
philpem@0 57 | |
philpem@0 58 | +-+-+-+
philpem@0 59 | | | | | +------------------------------------------------+
philpem@0 60 | | | | | | +------------------------------------+ |
philpem@0 61 | | | | | | | | |
philpem@0 62 +-------------+ | |
philpem@0 63 |7 6 5 4 3 2 1| | |
philpem@0 64 | | | |
philpem@0 65 | INT CONTRLR | | |
philpem@0 66 | | | |
philpem@0 67 |i i i | | |
philpem@0 68 |2 1 0 | | |
philpem@0 69 +-------------+ | |
philpem@0 70 | | | | |
philpem@0 71 | | | +--------------------------------+--+ | |
philpem@0 72 o o o | | | | |
philpem@0 73 +--------------+ +-------+ +----------+ +---------+ +----------+
philpem@0 74 | I I I a | | | | | | r a i | | i |
philpem@0 75 | 2 1 0 23 | | | | | | e c | | |
philpem@0 76 | | | | | | | a k | | |
philpem@0 77 | | | | | | | d | | |
philpem@0 78 | | | | | | | | | |
philpem@0 79 | M68000 | | ROM | | RAM | | IN | | OUT |
philpem@0 80 | | | | | | | | | |
philpem@0 81 | a9|--|a9 |--| |--| |--| |
philpem@0 82 | a8|--|a8 |--| |--| |--| |
philpem@0 83 | a7|--|a7 |--|a7 |--| |--| |
philpem@0 84 | a6|--|a6 |--|a6 |--| |--| |
philpem@0 85 | a5|--|a5 |--|a5 |--| |--| |
philpem@0 86 | a4|--|a4 |--|a4 |--| |--| |
philpem@0 87 | a3|--|a3 |--|a3 |--| |--| |
philpem@0 88 | a2|--|a2 |--|a2 |--| |--| |
philpem@0 89 | a1|--|a1 |--|a1 |--| |--| |
philpem@0 90 | a0|--|a0 |--|a0 |--| |--| |
philpem@0 91 | | | | | | | | | |
philpem@0 92 | d15|--|d15 |--|d15 |--| |--| |
philpem@0 93 | d14|--|d14 |--|d14 |--| |--| |
philpem@0 94 | d13|--|d13 |--|d13 |--| |--| |
philpem@0 95 | d12|--|d12 |--|d12 |--| |--| |
philpem@0 96 | d11|--|d11 |--|d11 |--| |--| |
philpem@0 97 | d10|--|d10 |--|d10 |--| |--| |
philpem@0 98 | d9|--|d9 |--|d9 |--| |--| |
philpem@0 99 | d8|--|d8 |--|d8 |--| |--| |
philpem@0 100 | d7|--|d7 |--|d7 |--|d7 |--|d7 |
philpem@0 101 | d6|--|d6 |--|d6 |--|d6 |--|d6 |
philpem@0 102 | d5|--|d5 |--|d5 |--|d5 |--|d5 |
philpem@0 103 | d4|--|d4 |--|d4 |--|d4 |--|d4 |
philpem@0 104 | d3|--|d3 |--|d3 |--|d3 |--|d3 |
philpem@0 105 | d2|--|d2 |--|d2 |--|d2 |--|d2 |
philpem@0 106 | d1|--|d1 |--|d1 |--|d1 |--|d1 w |
philpem@0 107 | d0|--|d0 |--|d0 |--|d0 |--|d0 r |
philpem@0 108 | | | | | | | | | i a |
philpem@0 109 | a F F F | | | | | | | | t c |
philpem@0 110 |22 rW 2 1 0 | | cs | | cs rW | | | | e k |
philpem@0 111 +--------------+ +-------+ +----------+ +---------+ +----------+
philpem@0 112 | | | | | | | | | |
philpem@0 113 | | | | | | | | | |
philpem@0 114 | | | | | +-------+ +-----+ | +---+ |
philpem@0 115 | | | | | | IC1 | | IC2 | | |AND| |
philpem@0 116 | | | | | |a b c d| |a b c| | +---+ |
philpem@0 117 | | | | | +-------+ +-----+ | | | |
philpem@0 118 | | | | | | | | | | | | | | +--+
philpem@0 119 | | | | | | | | | | | | | | |
philpem@0 120 | | | | | | | | | | | | | | |
philpem@0 121 | | | | | | | | | | | | | | |
philpem@0 122 | | | | +-----)-)-+-)----)-)-+ | | |
philpem@0 123 | | | +-------)-+---)----)-+ | | |
philpem@0 124 | | +---------+-----)----+ | | |
philpem@0 125 | | | | | |
philpem@0 126 | +------------------+-----------+----------------------+ |
philpem@0 127 | |
philpem@0 128 +-----------------------------------------------------------+
philpem@0 129
philpem@0 130 IC1: output=1 if a=0 and b=1 and c=0 and d=0
philpem@0 131 IC2: output=1 if a=0 and b=0 and c=1
philpem@0 132
philpem@0 133
philpem@0 134
philpem@0 135 Here is the listing for program.bin:
philpem@0 136 -----------------------------------
philpem@0 137
philpem@0 138 INPUT_ADDRESS equ $800000
philpem@0 139 OUTPUT_ADDRESS equ $400000
philpem@0 140 CIRCULAR_BUFFER equ $c0
philpem@0 141 CAN_OUTPUT equ $d0
philpem@0 142 STACK_AREA equ $100
philpem@0 143
philpem@0 144 vector_table:
philpem@0 145 00000000 0000 0100 dc.l STACK_AREA * 0: SP
philpem@0 146 00000004 0000 00c0 dc.l init * 1: PC
philpem@0 147 00000008 0000 0148 dc.l unhandled_exception * 2: bus error
philpem@0 148 0000000c 0000 0148 dc.l unhandled_exception * 3: address error
philpem@0 149 00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction
philpem@0 150 00000014 0000 0148 dc.l unhandled_exception * 5: zero divide
philpem@0 151 00000018 0000 0148 dc.l unhandled_exception * 6: chk
philpem@0 152 0000001c 0000 0148 dc.l unhandled_exception * 7: trapv
philpem@0 153 00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation
philpem@0 154 00000024 0000 0148 dc.l unhandled_exception * 9: trace
philpem@0 155 00000028 0000 0148 dc.l unhandled_exception * 10: 1010
philpem@0 156 0000002c 0000 0148 dc.l unhandled_exception * 11: 1111
philpem@0 157 00000030 0000 0148 dc.l unhandled_exception * 12: -
philpem@0 158 00000034 0000 0148 dc.l unhandled_exception * 13: -
philpem@0 159 00000038 0000 0148 dc.l unhandled_exception * 14: -
philpem@0 160 0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt
philpem@0 161 00000040 0000 0148 dc.l unhandled_exception * 16: -
philpem@0 162 00000044 0000 0148 dc.l unhandled_exception * 17: -
philpem@0 163 00000048 0000 0148 dc.l unhandled_exception * 18: -
philpem@0 164 0000004c 0000 0148 dc.l unhandled_exception * 19: -
philpem@0 165 00000050 0000 0148 dc.l unhandled_exception * 20: -
philpem@0 166 00000054 0000 0148 dc.l unhandled_exception * 21: -
philpem@0 167 00000058 0000 0148 dc.l unhandled_exception * 22: -
philpem@0 168 0000005c 0000 0148 dc.l unhandled_exception * 23: -
philpem@0 169 00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt
philpem@0 170 00000064 0000 0136 dc.l output_ready * 25: l1 irq
philpem@0 171 00000068 0000 010e dc.l input_ready * 26: l2 irq
philpem@0 172 0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq
philpem@0 173 00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq
philpem@0 174 00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq
philpem@0 175 00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq
philpem@0 176 0000007c 0000 014e dc.l nmi * 31: l7 irq
philpem@0 177 00000080 0000 0148 dc.l unhandled_exception * 32: trap 0
philpem@0 178 00000084 0000 0148 dc.l unhandled_exception * 33: trap 1
philpem@0 179 00000088 0000 0148 dc.l unhandled_exception * 34: trap 2
philpem@0 180 0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3
philpem@0 181 00000090 0000 0148 dc.l unhandled_exception * 36: trap 4
philpem@0 182 00000094 0000 0148 dc.l unhandled_exception * 37: trap 5
philpem@0 183 00000098 0000 0148 dc.l unhandled_exception * 38: trap 6
philpem@0 184 0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7
philpem@0 185 000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8
philpem@0 186 000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9
philpem@0 187 000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10
philpem@0 188 000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11
philpem@0 189 000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12
philpem@0 190 000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13
philpem@0 191 000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14
philpem@0 192 000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15
philpem@0 193 * This is the end of the useful part of the table.
philpem@0 194 * We will now do the Capcom thing and put code starting at $c0.
philpem@0 195
philpem@0 196 init:
philpem@0 197 * Copy the exception vector table to RAM.
philpem@0 198 000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index
philpem@0 199 000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors)
philpem@0 200 000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch
philpem@0 201 000000ce 2208 move.l a0, d1 * d1 is ROM index
philpem@0 202 000000d0 4481 neg.l d1
philpem@0 203 copy_table:
philpem@0 204 000000d2 22fb 18fe dc.l $22fb18fe * #%#$ as68k generates 020 code here
philpem@0 205 * move.l (copy_table,PC,d1.l), (a1)+
philpem@0 206 000000d6 5841 addq #4, d1
philpem@0 207 000000d8 51c8 fff8 dbf d0, copy_table
philpem@0 208
philpem@0 209 main_init:
philpem@0 210 * Initialize main program
philpem@0 211 000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT
philpem@0 212 000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6
philpem@0 213 000000e6 7c00 moveq #0, d6 * output buffer ptr
philpem@0 214 000000e8 7e00 moveq #0, d7 * input buffer ptr
philpem@0 215 000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask
philpem@0 216 main:
philpem@0 217 * Main program
philpem@0 218 000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output?
philpem@0 219 000000f2 67fa beq main
philpem@0 220 000000f4 be06 cmp.b d6, d7 * is there data?
philpem@0 221 000000f6 67f6 beq main
philpem@0 222 000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT
philpem@0 223 000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data
philpem@0 224 0000
philpem@0 225 00000106 5246 addq #1, d6
philpem@0 226 00000108 0206 000f andi.b #15, d6 * update circular buffer
philpem@0 227 0000010c 60e0 bra main
philpem@0 228
philpem@0 229
philpem@0 230 input_ready:
philpem@0 231 0000010e 2f00 move.l d0, -(a7)
philpem@0 232 00000110 2f01 move.l d1, -(a7)
philpem@0 233 00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data
philpem@0 234 00000118 1007 move.b d7, d0 * check if buffer full
philpem@0 235 0000011a 5240 addq #1, d0
philpem@0 236 0000011c 0200 000f andi.b #15, d0
philpem@0 237 00000120 bc00 cmp.b d0, d6
philpem@0 238 00000122 6700 000c beq input_ready_quit * throw away if full
philpem@0 239 00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data
philpem@0 240 0000012a 5247 addq #1, d7
philpem@0 241 0000012c 0207 000f andi.b #15, d7 * update circular buffer
philpem@0 242 input_ready_quit:
philpem@0 243 00000130 221f move.l (a7)+, d1
philpem@0 244 00000132 201f move.l (a7)+, d0
philpem@0 245 00000134 4e73 rte
philpem@0 246
philpem@0 247 output_ready:
philpem@0 248 00000136 2f00 move.l d0, -(a7)
philpem@0 249 00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT
philpem@0 250 0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt
philpem@0 251 00000144 201f move.l (a7)+, d0
philpem@0 252 00000146 4e73 rte
philpem@0 253
philpem@0 254 unhandled_exception:
philpem@0 255 00000148 4e72 2700 stop #$2700 * wait for NMI
philpem@0 256 0000014c 60fa bra unhandled_exception * shouldn't get here
philpem@0 257
philpem@0 258 nmi:
philpem@0 259 * perform a soft reset
philpem@0 260 0000014e 46fc 2700 move #$2700, SR * set status register
philpem@0 261 00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer
philpem@0 262 00000156 4e70 reset * reset peripherals
philpem@0 263 00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter
philpem@0 264
philpem@0 265 END
philpem@0 266
philpem@0 267
philpem@0 268
philpem@0 269 Compiling the example host environment:
philpem@0 270 --------------------------------------
philpem@0 271
philpem@0 272 The following assumes that you are using a GNU-based compiler such as gcc or
philpem@0 273 djgpp for DOS (available free from www.delorie.com).
philpem@0 274 If you are using a commercial compiler, you may have to modify the makefile
philpem@0 275 or generate your own project file.
philpem@0 276 Also note that part of the compilation process involves the compilation and
philpem@0 277 invokation of the m68kmake program.
philpem@0 278
philpem@0 279 - Copy the m68k files to a directory. Then copy the host environment files to
philpem@0 280 the same directory, overwriting m68kconf.h. program.bin is the actual 68000
philpem@0 281 program you will be running.
philpem@0 282 - Modify osd_get_key() in sim.c to suit your environment (currently set for
philpem@0 283 the free djgpp compiler, available from www.delorie.com, under DOS).
philpem@0 284 - Type make
philpem@0 285 - Perform the necessary animal sacrifices.
philpem@0 286 - Type sim program.bin
philpem@0 287
philpem@0 288
philpem@0 289 Keys:
philpem@0 290 ESC - quits the simulator
philpem@0 291 ~ - generates an NMI interrupt
philpem@0 292 Any other key - Genearate input for the input device
philpem@0 293
philpem@0 294
philpem@0 295 Note: I've cheated a bit in the emulation. There is no speed control
philpem@0 296 to set the speed the CPU runs at; it simply runs as fast as your
philpem@0 297 processor can run it.
philpem@0 298 To add speed control, you will need a high-precision timestamp
philpem@0 299 function (like the RDTSC instruction for newer Pentium CPUs)
philpem@0 300 and a bit of arithmetic to make the cycles argument for m68k_execute().
philpem@0 301 I'll leave that as an excercise to the reader.