1.1 diff -r 000000000000 -r 8bf1bf91a36d src/musashi/example/example.txt 1.2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 +++ b/src/musashi/example/example.txt Sat Nov 27 01:13:12 2010 +0000 1.4 @@ -0,0 +1,301 @@ 1.5 +EXAMPLE: 1.6 +------- 1.7 +As an example, I'll build an imaginary hardware platform. 1.8 + 1.9 + 1.10 +The system is fairly simple, comprising of a 000, an input device, an output 1.11 +device, a non-maskable-interrupt device, and an interrupt controller. 1.12 + 1.13 + 1.14 +The input device receives input from the user and asserts its interrupt 1.15 +request line until its value is read. Reading from the input device's 1.16 +memory-mapped port will both clear its interrupt request and read an ASCII 1.17 +representation (8 bits) of what the user entered. 1.18 + 1.19 +The output device reads value when it is selected through its memory-mapped 1.20 +port and outputs it to a display. The value it reads will be interpreted as 1.21 +an ASCII value and output to the display. The output device is fairly slow 1.22 +(it can only process 1 byte per second), and so it asserts its interrupt 1.23 +request line when it is ready to receive a byte. Writing to the output device 1.24 +sends a byte to it. If the output device is not ready, the write is ignored. 1.25 +Reading from the output device returns 0 and clears its interrupt request line 1.26 +until another byte is written to it and 1 second elapses. 1.27 + 1.28 +The non-maskable-interrupt (NMI) device, as can be surmised from the name, 1.29 +generates a non-maskable-interrupt. This is connected to some kind of external 1.30 +switch that the user can push to generate a NMI. 1.31 + 1.32 +Since there are 3 devices interrupting the CPU, an interrupt controller is 1.33 +needed. The interrupt controller takes 7 inputs and encodes the highest 1.34 +priority asserted line on the 3 output pins. the input device is wired to IN2 1.35 +and the output device is wired to IN1 on the controller. The NMI device is 1.36 +wired to IN7 and all the other inputs are wired low. 1.37 + 1.38 +The bus is also connected to a 1K ROM and a 256 byte RAM. 1.39 +Beware: This platform places ROM and RAM in the same address range and uses 1.40 + the FC pins to select the correct address space! 1.41 + (You didn't expect me to make it easy, did you? =) 1.42 + 1.43 +There are two ways to handle address spaces with Musashi: 1.44 + 1.45 +1. Enable M68K_SEPARATE_READS and make handler functions for immediate and 1.46 + pc-relative reads. 1.47 + 1.48 +2. Enable M68K_EMULATE_FC and make a callback function for function code 1.49 + changes. 1.50 + 1.51 +Both methods will work in this case, but I've opted for the "more correct" 1.52 +function code pin emulation for this example. 1.53 + 1.54 + 1.55 + 1.56 +Here is the schematic in all its ASCII splendour: 1.57 +------------------------------------------------- 1.58 + 1.59 + NMI TIED 1.60 + SWITCH LOW 1.61 + | | 1.62 + | +-+-+-+ 1.63 + | | | | | +------------------------------------------------+ 1.64 + | | | | | | +------------------------------------+ | 1.65 + | | | | | | | | | 1.66 + +-------------+ | | 1.67 + |7 6 5 4 3 2 1| | | 1.68 + | | | | 1.69 + | INT CONTRLR | | | 1.70 + | | | | 1.71 + |i i i | | | 1.72 + |2 1 0 | | | 1.73 + +-------------+ | | 1.74 + | | | | | 1.75 + | | | +--------------------------------+--+ | | 1.76 + o o o | | | | | 1.77 + +--------------+ +-------+ +----------+ +---------+ +----------+ 1.78 + | I I I a | | | | | | r a i | | i | 1.79 + | 2 1 0 23 | | | | | | e c | | | 1.80 + | | | | | | | a k | | | 1.81 + | | | | | | | d | | | 1.82 + | | | | | | | | | | 1.83 + | M68000 | | ROM | | RAM | | IN | | OUT | 1.84 + | | | | | | | | | | 1.85 + | a9|--|a9 |--| |--| |--| | 1.86 + | a8|--|a8 |--| |--| |--| | 1.87 + | a7|--|a7 |--|a7 |--| |--| | 1.88 + | a6|--|a6 |--|a6 |--| |--| | 1.89 + | a5|--|a5 |--|a5 |--| |--| | 1.90 + | a4|--|a4 |--|a4 |--| |--| | 1.91 + | a3|--|a3 |--|a3 |--| |--| | 1.92 + | a2|--|a2 |--|a2 |--| |--| | 1.93 + | a1|--|a1 |--|a1 |--| |--| | 1.94 + | a0|--|a0 |--|a0 |--| |--| | 1.95 + | | | | | | | | | | 1.96 + | d15|--|d15 |--|d15 |--| |--| | 1.97 + | d14|--|d14 |--|d14 |--| |--| | 1.98 + | d13|--|d13 |--|d13 |--| |--| | 1.99 + | d12|--|d12 |--|d12 |--| |--| | 1.100 + | d11|--|d11 |--|d11 |--| |--| | 1.101 + | d10|--|d10 |--|d10 |--| |--| | 1.102 + | d9|--|d9 |--|d9 |--| |--| | 1.103 + | d8|--|d8 |--|d8 |--| |--| | 1.104 + | d7|--|d7 |--|d7 |--|d7 |--|d7 | 1.105 + | d6|--|d6 |--|d6 |--|d6 |--|d6 | 1.106 + | d5|--|d5 |--|d5 |--|d5 |--|d5 | 1.107 + | d4|--|d4 |--|d4 |--|d4 |--|d4 | 1.108 + | d3|--|d3 |--|d3 |--|d3 |--|d3 | 1.109 + | d2|--|d2 |--|d2 |--|d2 |--|d2 | 1.110 + | d1|--|d1 |--|d1 |--|d1 |--|d1 w | 1.111 + | d0|--|d0 |--|d0 |--|d0 |--|d0 r | 1.112 + | | | | | | | | | i a | 1.113 + | a F F F | | | | | | | | t c | 1.114 + |22 rW 2 1 0 | | cs | | cs rW | | | | e k | 1.115 + +--------------+ +-------+ +----------+ +---------+ +----------+ 1.116 + | | | | | | | | | | 1.117 + | | | | | | | | | | 1.118 + | | | | | +-------+ +-----+ | +---+ | 1.119 + | | | | | | IC1 | | IC2 | | |AND| | 1.120 + | | | | | |a b c d| |a b c| | +---+ | 1.121 + | | | | | +-------+ +-----+ | | | | 1.122 + | | | | | | | | | | | | | | +--+ 1.123 + | | | | | | | | | | | | | | | 1.124 + | | | | | | | | | | | | | | | 1.125 + | | | | | | | | | | | | | | | 1.126 + | | | | +-----)-)-+-)----)-)-+ | | | 1.127 + | | | +-------)-+---)----)-+ | | | 1.128 + | | +---------+-----)----+ | | | 1.129 + | | | | | | 1.130 + | +------------------+-----------+----------------------+ | 1.131 + | | 1.132 + +-----------------------------------------------------------+ 1.133 + 1.134 +IC1: output=1 if a=0 and b=1 and c=0 and d=0 1.135 +IC2: output=1 if a=0 and b=0 and c=1 1.136 + 1.137 + 1.138 + 1.139 +Here is the listing for program.bin: 1.140 +----------------------------------- 1.141 + 1.142 + INPUT_ADDRESS equ $800000 1.143 + OUTPUT_ADDRESS equ $400000 1.144 + CIRCULAR_BUFFER equ $c0 1.145 + CAN_OUTPUT equ $d0 1.146 + STACK_AREA equ $100 1.147 + 1.148 + vector_table: 1.149 +00000000 0000 0100 dc.l STACK_AREA * 0: SP 1.150 +00000004 0000 00c0 dc.l init * 1: PC 1.151 +00000008 0000 0148 dc.l unhandled_exception * 2: bus error 1.152 +0000000c 0000 0148 dc.l unhandled_exception * 3: address error 1.153 +00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction 1.154 +00000014 0000 0148 dc.l unhandled_exception * 5: zero divide 1.155 +00000018 0000 0148 dc.l unhandled_exception * 6: chk 1.156 +0000001c 0000 0148 dc.l unhandled_exception * 7: trapv 1.157 +00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation 1.158 +00000024 0000 0148 dc.l unhandled_exception * 9: trace 1.159 +00000028 0000 0148 dc.l unhandled_exception * 10: 1010 1.160 +0000002c 0000 0148 dc.l unhandled_exception * 11: 1111 1.161 +00000030 0000 0148 dc.l unhandled_exception * 12: - 1.162 +00000034 0000 0148 dc.l unhandled_exception * 13: - 1.163 +00000038 0000 0148 dc.l unhandled_exception * 14: - 1.164 +0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt 1.165 +00000040 0000 0148 dc.l unhandled_exception * 16: - 1.166 +00000044 0000 0148 dc.l unhandled_exception * 17: - 1.167 +00000048 0000 0148 dc.l unhandled_exception * 18: - 1.168 +0000004c 0000 0148 dc.l unhandled_exception * 19: - 1.169 +00000050 0000 0148 dc.l unhandled_exception * 20: - 1.170 +00000054 0000 0148 dc.l unhandled_exception * 21: - 1.171 +00000058 0000 0148 dc.l unhandled_exception * 22: - 1.172 +0000005c 0000 0148 dc.l unhandled_exception * 23: - 1.173 +00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt 1.174 +00000064 0000 0136 dc.l output_ready * 25: l1 irq 1.175 +00000068 0000 010e dc.l input_ready * 26: l2 irq 1.176 +0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq 1.177 +00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq 1.178 +00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq 1.179 +00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq 1.180 +0000007c 0000 014e dc.l nmi * 31: l7 irq 1.181 +00000080 0000 0148 dc.l unhandled_exception * 32: trap 0 1.182 +00000084 0000 0148 dc.l unhandled_exception * 33: trap 1 1.183 +00000088 0000 0148 dc.l unhandled_exception * 34: trap 2 1.184 +0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3 1.185 +00000090 0000 0148 dc.l unhandled_exception * 36: trap 4 1.186 +00000094 0000 0148 dc.l unhandled_exception * 37: trap 5 1.187 +00000098 0000 0148 dc.l unhandled_exception * 38: trap 6 1.188 +0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7 1.189 +000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8 1.190 +000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9 1.191 +000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10 1.192 +000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11 1.193 +000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12 1.194 +000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13 1.195 +000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14 1.196 +000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15 1.197 + * This is the end of the useful part of the table. 1.198 + * We will now do the Capcom thing and put code starting at $c0. 1.199 + 1.200 + init: 1.201 + * Copy the exception vector table to RAM. 1.202 +000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index 1.203 +000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors) 1.204 +000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch 1.205 +000000ce 2208 move.l a0, d1 * d1 is ROM index 1.206 +000000d0 4481 neg.l d1 1.207 + copy_table: 1.208 +000000d2 22fb 18fe dc.l $22fb18fe * #%#$ as68k generates 020 code here 1.209 + * move.l (copy_table,PC,d1.l), (a1)+ 1.210 +000000d6 5841 addq #4, d1 1.211 +000000d8 51c8 fff8 dbf d0, copy_table 1.212 + 1.213 + main_init: 1.214 + * Initialize main program 1.215 +000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT 1.216 +000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6 1.217 +000000e6 7c00 moveq #0, d6 * output buffer ptr 1.218 +000000e8 7e00 moveq #0, d7 * input buffer ptr 1.219 +000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask 1.220 + main: 1.221 + * Main program 1.222 +000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output? 1.223 +000000f2 67fa beq main 1.224 +000000f4 be06 cmp.b d6, d7 * is there data? 1.225 +000000f6 67f6 beq main 1.226 +000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT 1.227 +000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data 1.228 + 0000 1.229 +00000106 5246 addq #1, d6 1.230 +00000108 0206 000f andi.b #15, d6 * update circular buffer 1.231 +0000010c 60e0 bra main 1.232 + 1.233 + 1.234 + input_ready: 1.235 +0000010e 2f00 move.l d0, -(a7) 1.236 +00000110 2f01 move.l d1, -(a7) 1.237 +00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data 1.238 +00000118 1007 move.b d7, d0 * check if buffer full 1.239 +0000011a 5240 addq #1, d0 1.240 +0000011c 0200 000f andi.b #15, d0 1.241 +00000120 bc00 cmp.b d0, d6 1.242 +00000122 6700 000c beq input_ready_quit * throw away if full 1.243 +00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data 1.244 +0000012a 5247 addq #1, d7 1.245 +0000012c 0207 000f andi.b #15, d7 * update circular buffer 1.246 + input_ready_quit: 1.247 +00000130 221f move.l (a7)+, d1 1.248 +00000132 201f move.l (a7)+, d0 1.249 +00000134 4e73 rte 1.250 + 1.251 + output_ready: 1.252 +00000136 2f00 move.l d0, -(a7) 1.253 +00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT 1.254 +0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt 1.255 +00000144 201f move.l (a7)+, d0 1.256 +00000146 4e73 rte 1.257 + 1.258 + unhandled_exception: 1.259 +00000148 4e72 2700 stop #$2700 * wait for NMI 1.260 +0000014c 60fa bra unhandled_exception * shouldn't get here 1.261 + 1.262 + nmi: 1.263 + * perform a soft reset 1.264 +0000014e 46fc 2700 move #$2700, SR * set status register 1.265 +00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer 1.266 +00000156 4e70 reset * reset peripherals 1.267 +00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter 1.268 + 1.269 + END 1.270 + 1.271 + 1.272 + 1.273 +Compiling the example host environment: 1.274 +-------------------------------------- 1.275 + 1.276 +The following assumes that you are using a GNU-based compiler such as gcc or 1.277 +djgpp for DOS (available free from www.delorie.com). 1.278 +If you are using a commercial compiler, you may have to modify the makefile 1.279 +or generate your own project file. 1.280 +Also note that part of the compilation process involves the compilation and 1.281 +invokation of the m68kmake program. 1.282 + 1.283 +- Copy the m68k files to a directory. Then copy the host environment files to 1.284 + the same directory, overwriting m68kconf.h. program.bin is the actual 68000 1.285 + program you will be running. 1.286 +- Modify osd_get_key() in sim.c to suit your environment (currently set for 1.287 + the free djgpp compiler, available from www.delorie.com, under DOS). 1.288 +- Type make 1.289 +- Perform the necessary animal sacrifices. 1.290 +- Type sim program.bin 1.291 + 1.292 + 1.293 +Keys: 1.294 + ESC - quits the simulator 1.295 + ~ - generates an NMI interrupt 1.296 + Any other key - Genearate input for the input device 1.297 + 1.298 + 1.299 +Note: I've cheated a bit in the emulation. There is no speed control 1.300 + to set the speed the CPU runs at; it simply runs as fast as your 1.301 + processor can run it. 1.302 + To add speed control, you will need a high-precision timestamp 1.303 + function (like the RDTSC instruction for newer Pentium CPUs) 1.304 + and a bit of arithmetic to make the cycles argument for m68k_execute(). 1.305 + I'll leave that as an excercise to the reader.