Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 18:49 29 Mar 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : WIP: CMM2 NES Emulator

     Page 2 of 4    
Author Message
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 03:41pm 31 Jul 2020
Copy link to clipboard 
Print this post

That's what the little blue box is lol. It's a USB hdmi capture box (which I highly recommend) and I'm using a crappy little vga to hdmi adapter with it. I mean, it works, but doesn't look the best. You can see the capture on the right side and the terminal running on the left side of the screen
 
Shadamus
Newbie

Joined: 26/07/2020
Location: United States
Posts: 17
Posted: 03:42pm 31 Jul 2020
Copy link to clipboard 
Print this post

Excellent!
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 2989
Posted: 04:03pm 31 Jul 2020
Copy link to clipboard 
Print this post

Looks like a useful arrangement. Are you getting vga output from the CMM2 to display on your laptop screen?

Can you explain the parts--hardware and software--a little more fully?
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 07:21pm 31 Jul 2020
Copy link to clipboard 
Print this post

Well, firstly, it requires power lol (power is still out and it's so hot,  I'm melting...)

This is the capture card. It's hdmi in, USB out (says usb 3, but its working on a USB 2 connection surprisingly. Maybe won't do hi res or audio through usb 2)). It also recieves power through the same cable. It has a hdmi passthrough too, which works so long as the device has power (whether the computer is on or not). I highly recommend it.

https://www.amazon.co.uk/gp/aw/d/B081RS3NH3?psc=1&ref=ppx_pop_mob_b_asin_title

This is the vga to hdmi adapter I'm using in that screenshot. I do not recommend it. It's not aligned properly, cuts out for a few seconds occasionally and has interference. It's not good. But it's low power, so I used it in this situation.
https://www.amazon.co.uk/gp/aw/d/B07F7WYGHV?psc=1&ref=ppx_pop_mob_b_asin_title

For software, I use tera term for serial connection to the cmm2. To capture the video, if you just want to view it, you can use Windows camera software (windows 10). It works well enough. Very much a plug and go connection. It will stretch to 16:9 though.
If you want more control over the video capture, you can use OBS. You can add the device and then you can create a windowed projector of it so you can move it around and resize it to fit your available screen space. You can also set a filter on it for 4:3 output (native aspect ratio for cmm2).

In cmm2, I use "OPTION CONSOLE SERIAL" so that the print command prints to the terminal and the graphics display on the video capture. This does have a small decrease on performance, but it's been a lifesaver.

I think that's it. Quick and simple to say up but does cost upwards of £70 or more, depending on what you get and where you get it.
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 2989
Posted: 08:59pm 31 Jul 2020
Copy link to clipboard 
Print this post

Thanks. I think I'm getting it. So a device like this vga-hdmi module (I know some don't work well) connected with a M-M HDMI cable to something like this HDMI-USB3 module (second option)?

And then standard win10 camera software can see the video input on the usb port and stream it to the program's window on the laptop?

That would be too cool (well, perhaps not cool enough if it's hot without power where you are, as it would be where I am (Nova Scotia)).
Edited 2020-08-01 07:03 by lizby
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 09:53pm 31 Jul 2020
Copy link to clipboard 
Print this post

The USB hdmi adapter works with lots of unusual resolutions and has always just worked. Cheap ones like what you linked are no where near as good. I can not recommend that one. It's upto you to try though and if you do, I hope it works out well
 
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 12:44pm 01 Aug 2020
Copy link to clipboard 
Print this post



So, as is the case with everything in programming... you fix one bug, and a whole bunch more show up.

So, this looks AWFUL. But that's ok. It's ok because its showing that the palette was changed for the donkey kong text, the player 1 and 2 text and the nintendo copywrite info. because it wasn't changing the palette bank before, but now it is. I just have to fix the colours being loaded into the banks now..

For clarity. The Picture Processing Unit (PPU) has 64 colours. Only 32 can be loaded into 8 banks of 4 at a time. The palettes can be changed when the rendering is switched off (after the vblank flag gets set to 0). Thats how mario does it's flashing coins and blocks. It swaps the palette in one of the banks each frame.

There's a lot more to it than that of course, but that'll be enough to explain what I meant about the text getting different palettes.

Now back to fixing more bugs.
 
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 03:39pm 01 Aug 2020
Copy link to clipboard 
Print this post

Ok, we're back to drawing as before.

So, I have some questions regarding drawing to the screen.

At the moment, as the scanlines iterate through a complex loop of statements, the PPU draws a single pixel to the screen each loops.

so,
scanline 1 (actually starts at -1, but thats not important in this post), ppucycle 0 to 256 (goes to 340, but only 256 are drawn) get drawn, one at a time.
repeat until scanline 240 (goes to 260, but only 240 are active on screen)
off screen stuff happens for the last 20 scanlines.
thats one frame complete.
repeat from beginning.

the way im currently drawing to the screen is with
PIXEL ppucycle - 1, scanline, palette(ppuread((&H3F00 + (PALFINAL << 2) + PIXFINAL) AND &H3F))

now, I know theres a lot going on in the colour part, but thats because of the palette selection and stuff. It has to read from the ppu to know what colour to draw.

Is there a better way of drawing pixels on the screen? I know its currently drawing as fast as the code is cycling through the ppu (which takes a long time to complete one frame..) but... i'm not sure why the palette isn't being swapped properly, thats the thing...
Edited 2020-08-02 01:57 by Atomizer_Zero
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 04:21pm 01 Aug 2020
Copy link to clipboard 
Print this post

I've just watched the first OLC NES video showing the NES architecture. You have certainly taken on a task!

My first thoughts below:

I would work in mode 3,12. Then the background is going to be displayed from PAGE 0 and the sprites from PAGE 1. You then have 4096 colours available ARGB4444. As you aren't interested in transparency the pixels will all be 16bit with the top 4 bits set to 1. i.e. 0xFRGB.

Each palette will just map the 6-bit code to a specific 0xFRGB level

I would then ignore the PIXEL command and write direct to the video memory using POKE SHORT. The graphics primer includes a section as to how the pixels are arranged in memory. Assume you use Page 2 for the working background and page 3 for the sprites. Use PAGE COPY 2 to 0 and PAGE COPY 3 to 1 to move the working memory to the display during frame blanking.

I haven't got to the "Mapper" section of the PPU yet but this seems like you would simply use other video pages rather than 2 and 3 as the working areas.

For the 6502 code itself I would store it in a LongString and then you can read each byte with LGETBYTE(). If the game has more than 1 code mapping then you will have a longstring per map.

This may all be rubbish so use or abuse as you wish
 
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 06:13pm 01 Aug 2020
Copy link to clipboard 
Print this post

I think I follow what you're saying.

Using POKE SHORT would be fine, if the ppu was running full speed, as the time it takes to set those points on the screen is heavily bottlenecked by the ppu2c02 and the cpu6502. Also, I can't quite get my head around POKE to begin with... it's certainly something new to me.

When trying to use POKE, I get "Error: Address not divisible by 2".

What I tried
pix% = mm.info(page address 0)
poke short pix%+scanline+ppucycle, MAP(PPUREAD(&H3F00 + (PALFINAL << 2) + PIXFINAL,0))


So, loop one would be
"pix% + 0 + 0", which is fine.
next loop
"pix% + 0 + 1", which errors out as mentioned.


Now, I'm confused because, from what I read in the graphics programming guide says
"OK, so we know that in 800x600x8 resolution the screen is using 480KB of memory starting at &H24000000. This
memory is organised exactly as you would expect. The first 800 bytes are the top line of the display starting at the top
left hand corner. The second 800 bytes are the second line of the display. and the 480,000th byte is the bottom right of
the display"

Im using MODE 3,8 right now (it complained that I can't use MAP in MODE 3,12).
so, the first 320 bytes should be scanline 0. the second 320 bytes should be scanline 1.

I'm most likely understanding this wrong, but I want to learn. Thanks.

EDIT:
You can consider scanline to be the Y position and ppucycle to be the X position. The NES resolution is 256 x 240.

EDIT2:
Oh, well, it works with POKE BYTE. Also, did "pix%+ppucycle*mm.hres+ppucycle"
waiting for it to fully render the title screen for donkey kong before I'll know if it is actually "working" though

EDIT3:
NO. it didn't work lol. Because im dumb and i dont need the "*mm.hres".

trying again...
Edited 2020-08-02 05:23 by Atomizer_Zero
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 08:00pm 01 Aug 2020
Copy link to clipboard 
Print this post

  Quote  Im using MODE 3,8 right now (it complained that I can't use MAP in MODE 3,12).
so, the first 320 bytes should be scanline 0. the second 320 bytes should be scanline 1.

In mode 3 all lines are duplicated so the real resolution is 320x400. If you use mode 3,12 you shouldn't need the MAP command at all (and as you say can't use it). Just use the nearest RGB444 value to the colour you want. Mode 3,12 uses 16 bits per pixel so all bytes in the framestore are on  even memory locations
Edited 2020-08-02 16:34 by matherp
 
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 12:44pm 03 Aug 2020
Copy link to clipboard 
Print this post

I'm rewriting the PPU in an attempt to gain a little more speed out of it (probably fruitless, but I have to try..)

Theres one part of my code where I need to flip a byte.
For example,

&B00000111   becomes
&B11100000


currently, im just doing this

https://stackoverflow.com/questions/2602823/in-c-c-whats-the-simplest-way-to-reverse-the-order-of-bits-in-a-byte/2602885#2602885

Function flipByte(b)
   b = ((b And &HF0) >> 4) Or ((b And &H0F) << 4)
   b = ((b And &HCC) >> 2) Or ((b And &H33) << 2)
   b = ((b And &HAA) >> 1) Or ((b And &H55) << 1)
flipByte = b
End Function


Is there a quicker way in MMBasic? Should I make this a CSUB?! O_O
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3807
Posted: 12:54pm 03 Aug 2020
Copy link to clipboard 
Print this post

  Atomizer_Zero said  Is there a quicker way in MMBasic? Should I make this a CSUB?! O_O


You could use a CSUB, but you also have shed loads of memory - use a lookup table/array, even with 256 8-byte integers that's still only 2 KB and you've got 5 MB to play with.

Tom
Edited 2020-08-03 22:54 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
Atomizer_Zero
Senior Member

Joined: 04/07/2020
Location: United Kingdom
Posts: 134
Posted: 01:12pm 03 Aug 2020
Copy link to clipboard 
Print this post

I'm not entirely sure how to do a lookup table to be honest..  

I'm not sure if it's worth it either. It doesn't get used THAT much... and only when a bunch of particular circumstances are met...
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3807
Posted: 01:21pm 03 Aug 2020
Copy link to clipboard 
Print this post

  Atomizer_Zero said  I'm not entirely sure how to do a lookup table to be honest..  

I'm not sure if it's worth it either. It doesn't get used THAT much... and only when a bunch of particular circumstances are met...


Like so (assuming I haven't cocked up):

' Call this once at the global level to put flip_byte%() into the global variable list.
Sub init_flip_byte()
 Dim flip_byte%(255) ' assuming option base 0
 Local i
 For i = 0 To 255
   flip_byte%(i) = flipByte(i) ' I'd probably inline your function here
 Next i
End Sub


And then if you want to flip x then just do:

y = flip_byte%(x)


Which replaces a subroutine call, 6 shifts, 6 ANDs, 3 ORs and ~10 variable lookups with a single array lookup.

Regards,

Tom
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3807
Posted: 01:28pm 03 Aug 2020
Copy link to clipboard 
Print this post

Also, in case you haven't noticed, I think your existing function not only returns the flipped value of 'b' but also simultaneously flips 'b' in place because it is passed by reference.
Edited 2020-08-03 23:28 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 01:38pm 03 Aug 2020
Copy link to clipboard 
Print this post

Here you go


B%=&B11100001
bytereverse b%, c%
? bin$(c%)
'
CSUB bytereverse
00000000
7802B4F0 18942300 0503EB43 EA4302AB 02A25394 416B1912 EA45051D 05143512
416B1912 E9D5A50C 40224500 0218402B EA400216 023D6712 6516EA45 19A40234
042F417D 4714EA47 19A40426 18A4417D 700D415D 4770BCF0 84422110 00000008
End CSUB

Edited 2020-08-03 23:40 by matherp
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3807
Posted: 01:40pm 03 Aug 2020
Copy link to clipboard 
Print this post

  matherp said  Here you go


Now I want to know which approach is faster.

Tom
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 01:41pm 03 Aug 2020
Copy link to clipboard 
Print this post

Note just updated with "optimised" version

void bytereverse(unsigned char *b, unsigned char *c){
*c = ((*b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
}

Edited 2020-08-03 23:42 by matherp
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3807
Posted: 01:55pm 03 Aug 2020
Copy link to clipboard 
Print this post

Table lookup appears to be marginally faster in this case:

> list
init_flip_byte()

t = Timer
For j% = 0 To 255
 y% = flip_byte%(j%)
 Print y%;
Next j%
Print
Print Timer - t
Print

t = Timer
For j% = 0 To 255
 bytereverse j%, y%
 Print y%;
Next j%
Print
Print Timer - t

Sub init_flip_byte()
 Dim flip_byte%(255)
 Local i%, y%
 For i% = 0 To 255
   bytereverse i%, y%
   flip_byte%(i%) = y%
 Next i%
End Sub

CSUB bytereverse
00000000
7802B4F0 18942300 0503EB43 EA4302AB 02A25394 416B1912 EA45051D 05143512
416B1912 E9D5A50C 40224500 0218402B EA400216 023D6712 6516EA45 19A40234
042F417D 4714EA47 19A40426 18A4417D 700D415D 4770BCF0 84422110 00000008
End CSUB

>
> run
0 128 64 192 32 160 96 224 16 144 80 208 48 176 112 240 8 136 72 200 40 168 104 232 24 152 88 216 56 184 120 248 4 132 68 196 36 164 100 228 20 148 84 212 52 180 116 244 12 140 76 204 44 172 108 236 28 156 92 220 60 188 124 252 2 130 66 194 34 162 98 226 18 146 82 210 50 178 114 242 10 138 74 202 42 170 106 234 26 154 90 218 58 186 122 250 6 134 70 198 38 166 102 230 22 150 86 214 54 182 118 246 14 142 78 206 46 174 110 238 30 158 94 222 62 190 126 254 1 129 65 193 33 161 97 225 17 145 81 209 49 177 113 241 9 137 73 201 41 169 105 233 25 153 89 217 57 185 121 249 5 133 69 197 37 165 101 229 21 149 85 213 53 181 117 245 13 141 77 205 45 173 109 237 29 157 93 221 61 189 125 253 3 131 67 195 35 163 99 227 19 147 83 211 51 179 115 243 11 139 75 203 43 171 107 235 27 155 91 219 59 187 123 251 7 135 71 199 39 167 103 231 23 151 87 215 55 183 119 247 15 143 79 207 47 175 111 239 31 159 95 223 63 191 127 255
19.526

0 128 64 192 32 160 96 224 16 144 80 208 48 176 112 240 8 136 72 200 40 168 104 232 24 152 88 216 56 184 120 248 4 132 68 196 36 164 100 228 20 148 84 212 52 180 116 244 12 140 76 204 44 172 108 236 28 156 92 220 60 188 124 252 2 130 66 194 34 162 98 226 18 146 82 210 50 178 114 242 10 138 74 202 42 170 106 234 26 154 90 218 58 186 122 250 6 134 70 198 38 166 102 230 22 150 86 214 54 182 118 246 14 142 78 206 46 174 110 238 30 158 94 222 62 190 126 254 1 129 65 193 33 161 97 225 17 145 81 209 49 177 113 241 9 137 73 201 41 169 105 233 25 153 89 217 57 185 121 249 5 133 69 197 37 165 101 229 21 149 85 213 53 181 117 245 13 141 77 205 45 173 109 237 29 157 93 221 61 189 125 253 3 131 67 195 35 163 99 227 19 147 83 211 51 179 115 243 11 139 75 203 43 171 107 235 27 155 91 219 59 187 123 251 7 135 71 199 39 167 103 231 23 151 87 215 55 183 119 247 15 143 79 207 47 175 111 239 31 159 95 223 63 191 127 255
22.166


Note I get some weird timings from this:
- if you EDIT the program and F2 then each loop takes ~10 ms to run
- if you then RUN it still takes ~10 ms
- if you RUN again it takes ~20 ms
- and 20 ms for all subsequent RUNs

Explanation?

Regards,

Tom
Edited 2020-08-04 00:02 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
     Page 2 of 4    
Print this page
© JAQ Software 2024